Scrapy——基本用法(命令行工具、Item、Spiders)

命令行工具

创建项目

scrapy startproject myproject

该命令经会在myproject目录中创建一个Scrapy项目。进入到项目根目录,就可以使用scrapy命令来管理和控制你的项目了。
控制项目
有些Scrapy命令要求在Scrapy项目中运行。另外注意,有些命令在项目里运行时的效果有些区别。

scrapy <command> -h

查看所有可用命令

scrapy -h

Scrapy提供了两种类型的命令。一种是必须在scrapy项目中运行,另一种则不与需要。

全局命令:

命令 语法 功能
startproject scrapy startproject [project_name] 创建项目
settings scrapy settings [options] 在项目中运行时,该命令将会输出醒目的设定值,否则输出Scrapy默认设定
runspider scrapy runspider spider_file.py 在未创建项目的情况下,运行一个在Python文件中的spider
shell scrapy shell [url] 以给定的URL或者空启动Scrapy
fetch scrapy fetch [url] 使用Scrapy下载器下载给定的URL,并将获取到的内容送到标准输出。
view scrapy view [url] 在浏览器中打开给定的URL,并以Scrapy spider获取到的形式展现,可以用来检查spider所获取到的页面
version scrapy version [-v] 输出scrapy版本,配合-v运行时,该命令将同时输出python,Twisted以及平台的信息,方便bug提交


项目命令

命令 语法 功能
crawl scrapy crawl <spider> 使用spider进行爬取
check scrapy check [-l] <spider> 运行contract检查
list scrapy list 列出当前项目种所有可用的spider
edit scrapy edit <spider> 使用EDITOR种设定的编辑器给定的spider
parse scrapy parse <url> [options] 获取给定的URL并使用响应的spider分析处理。
genspider scrapy genspider [-t template] <name> <domain> 仅仅是创建spider的一种快捷方法。该方法可以用提前定义好的模板来生成spider,也可以自己创建spider的源码文件
deploy `scrapy deploy [ -l
bench scrapy bench 运行benchmark测试

parse命令参数选项

  • --spider=SPIDER:跳过自动检测spider并强制使用特定的spider;
  • --a NAME=VALUE:设置spider的参数
  • --callback-cspider中用于解析返回的回调函数
  • --pipelines:在pipeline中处理item
  • --rules-r:使用CrawlSpider规则来发现用来解析返回的回调函数
  • --noitems不显示爬取道的item
  • --nolinks不显示爬取到的链接
  • --nocolour避免使用pygments对输出着色
  • --depth-d指定跟进链接诶请求的层数默认为1
  • --verbose-v显示每个请求的详细信息

Items

爬取的主要目的就是从非结构性的数据源提取结构性数据。Scrapy提供Item类来满足这样的需求。Item对象是种简单的容器,保存了爬取到的数据。其提供了类似于字典的API以及用于声明可用字段的简单语法。
声明Item

class Product(scrapy.Item):
    name=scrapy.Field()
    price=scrapy.Field()
    stock=scrapy.Field()
    last_updated=scrapy.Field(serializer=str)

Item字段
Field对象指明了每个字段的元数据。你可以为每个字段指明任何类型的元数据。设置Field对象的主要目的就是在一个地方定义好所有的元数据。
与Item配合
创建item

>>> product = Product(name='Desktop PC', price=1000)
>>> print product
Product(name='Desktop PC', price=1000)

获取字段值

>>> product['name']
Desktop PC
>>> product.get('name')
Desktop PC

>>> product['price']
1000

>>> product['last_updated']
Traceback (most recent call last):
    ...
KeyError: 'last_updated'

>>> product.get('last_updated', 'not set')
not set

>>> product['lala'] # getting unknown field
Traceback (most recent call last):
    ...
KeyError: 'lala'

>>> product.get('lala', 'unknown field')
'unknown field'

>>> 'name' in product  # is name field populated?
True

>>> 'last_updated' in product  # is last_updated populated?
False

>>> 'last_updated' in product.fields  # is last_updated a declared field?
True

>>> 'lala' in product.fields  # is lala a declared field?
False

设置字段值

>>> product['last_updated'] = 'today'
>>> product['last_updated']
today

>>> product['lala'] = 'test' # setting unknown field
Traceback (most recent call last):
    ...
KeyError: 'Product does not support field: lala'

获取所有获取到的值

  print product.keys()
    # ['price', 'name']
    print product.items()
    # [('price', 1000), ('name', 'Desktop PC')]

复制item

   product2=Product(product)
    print product2
#     {'name': 'Desktop PC', 'price': 1000}

    product3=product2.copy()
    print product3
#     {'name': 'Desktop PC', 'price': 1000}

根据item创建字典

   print dict(product)
    # {'price': 1000, 'name': 'Desktop PC'}

根据字典创建item

    print Product({'name': 'Laptop PC', 'price': 1500})
#     {'name': 'Laptop PC', 'price': 1500}

扩展Item
可以通过继承原始的Item来扩展item

class DiscountedProduct(Product):
    discount_percent = scrapy.Field(serializer=str)
    discount_expiration_date = scrapy.Field()

也可以通过使用原字段的元数据,添加新的值或修改原来的值来扩展字段元数据。

class SpecificProduct(Product):
    name = scrapy.Field(Product.fields['name'], serializer=my_serializer)

Item对象

class scrapy.item.Item([arg])

返回一个根据给定参数可选初始化的item,Item读值了标准的dict API。包括初始化函数也相同,为以额外添加的属性是:field,一个包含了所有声明的字段的字典,而不仅仅是货渠道的字段。

Spiders

Spider类定义了如何爬取某个网站,包括了爬取的动作以及如何从网页的内容中提取结构化数据。还句话说,Spider就是你定义爬取的动作及分析某个网页的地方。

  • 以初始的URL初始化Request,并设置回调函数。当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。start_requests()读取start_urls中的URL,并以parse为回调函数生成Request.
  • 在回调函数内分析返回的网页内容,返回Item对象或者Request或者一个包含二者的可迭代容器。返回的Request对象之后回经过Scrapy处理,下载相应的内容,并调用设置的callback函数。
  • 在回调函数内,你可以使用选择器来分析网页内容,并根据分析的数据生成item。
  • 最后,由spider返回的item将被存到数据库或使用Feed exports存到文件中。

Spider参数
Spider可以通过接收参数来修改其功能。spider参数一般用来定义初始URL或者指定先值爬取网站的部分。
在运行crawl时添加-a可以传递Spider参数:

scrapy crawl myspider -a category=electronics

Spider在构造器中获取参数。

import scrapy

class MySpider(Spider):
    name = 'myspider'

    def __init__(self, category=None, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.start_urls = ['http://www.example.com/categories/%s' % category]
        # ...

Spider

class scrapy.spider.Spider

Spider是最简单的spider。每个器它的spider必须继承自该类。Spider仅仅请求给定的
start_urls/start_requests,并根据返回的结果(resulting/responses)调用spider的parse方法。

  • name:定义spider名字的字符串。定义了Scrapy如何定位spider,必须是唯一的。不过可以生成多个相同的spider实例。
    如果该spider爬取单个网站,一个常见的做法是以该网站来命名spider。
  • allowed_domains:可选,包含了spider允许爬取的域名列表。当offsiteMiddleware启用时,域名不在列表中的URL不会被跟进。
  • **start_urls:**URL列表,当没有制定特定的URL时,spider将从该列表中来时进行爬取。因此,第一个被获取到的页面的URL将是该列表之一。后续的URL将会从获取到的数据中提取。
  • start_requests():该方法必须返回一个可迭代对象。该对象包含了spider用于爬取的第一个Request。当spider启动爬取并且未指定URL时,该方法被调用。当指定了URL时,make_requests_from_url()将被调用来创建Request对象。仅近乎uibei调用一次,可视为生成器。该方法默认使用start_urls的url生成Reqest。如果你想修改最初爬取某个网站的Request对象,可以重写该方法。
  • make_requests_from_url(url):该方法接收一个URL并返回用于爬取的Request对象。在初始化时被start_requests()调用,也用于转化url为request。默认未被复写的情况下该方法返回的Request对象中,parse()作为回调函数,dont_filter参数也被设置为开启。
  • parse(respone):当response没有指定回调函数时,该方法时Scapy处理下载的response的默认方法。
    parse负责处理respones并返回处理的数据以及跟进的URL。
    Spider对其他的Request及Item的可迭代的对象。
  • *log(message[,level,component]):使用scrapy.log.msg()方法记录message。log中自动带上该spider的name属性。
  • closed(reason):当spider关闭时,该函数被调用。该方法提供了一个提到调用signals.connect()来监听spider_closed信号的快捷方式。
    样例
import scrapy

class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = [
        'http://www.example.com/1.html',
        'http://www.example.com/2.html',
        'http://www.example.com/3.html',
    ]

    def parse(self, response):
        self.log('A response from %s just arrived!' % response.url)

CrawlSpider

class scrapy.contrib.spiders.CrawlSpider

爬取一般网站常用的spider。其定义了一些规则来提供跟link的方便机制。除了继承过来的属性外,其提供了一个新的属性。

  • rules:一个包含一个或多个Rule对象的集合。每个Rule对爬取网站的动作定义了特定的表现。如果rule匹配了相同的链接,则根据它们在本属性中被定义的顺序,第一个会被使用。
  • parse_start_url(response):当start_url的请求返回时,该方法被调用。该方法分析最初的返回值并必须返回一个 Item 对象或者 一个 Request 对象或者 一个可迭代的包含二者对象。

爬取规则(Crawling rules)

class scrapy.contrib.spiders.Rule(link_extractor, callback=None, 
cb_kwargs=None, follow=None, process_links=None, process_request=None)
  • link_extractor是一个Link Extractor对象,其定义了如何从爬取到的页面提取链接。
  • callback是一个callable或string。从link_extractor中每获取到链接时将调用该函数。该回调函数接受一个response作为其第一个参数,并返回一个包含Itm以及Request对象的列表。
  • cb_kwargs:包含传递给回调函数的参数的字典。
  • follow是一个布尔值,指定了根据该规则从response提取的链接是否需要跟进。如果callback为None,follow默认设置为True,否则默认为False。
  • process_link是一个callable或string。主要用来过滤。
  • process_reqeust是一个callable或string。该规则提取到每个request时都会调用该函数。该函数必须返回一个request或None.
# coding:utf-8

import scrapy
from scrapy.contrib.spiders import CrawlSpider,Rule
from scrapy.contrib.linkextractors import LinkExtractor



class MySpider(CrawlSpider):
    name='example.com'
    # 允许爬取链接的域名
    allowed_domains=['example.com']
    start_urls=['http://www.example.com']


    rules=(
        # # 提取匹配 'category.php' (但不匹配 'subsection.php') 的链接并跟进链接(没有callback意味着follow默认为True)
        Rule(LinkExtractor(allow=('category\.php'),deny=('subsection\.php'))),
        # # 提取匹配 'item.php' 的链接并使用spider的parse_item方法进行分析
        Rule(LinkExtractor(allow=('item\.php'),callback='parse_item')),
    )

    def parse_item(self,response):
        self.log('Hi, this is an item page! %s' % response.url)
        item=scrapy.Item()
        item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
        item['name'] = response.xpath('//td[@id="item_name"]/text()').extract()
        item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()
        return item

该spider将从example.com的首页开始爬取,获取category以及item的链接并对后者使用parse_item方法。当item获得返回时,将使用XPath处理HTML并生成一些数据填入Item中。
XMLFeedSpider

class scrapy.contrib.spiders.XMLFeedSpider

XMLFeedSpider被设计用于通过迭代各个节点来分析XML源。迭代其可以从iternodes,xml,html选择。鉴于xml以及html迭代器需要先读取所有DOM再分析而引起的性能问题,一般还是推荐使用iternodes。

你必须定义下列类属性来设置迭代器以及标签名:

iterator:用于确定使用哪个迭代器,

  • iternodes-一个高性能的基于正则表达式的迭代器;
  • html'-使用selector的迭代器。使用DOM进行分析,其需要将所有的DOM载入内存,当数据量大的时候会产生问题。
  • xml-和html一样。
    默认值为iternodes。

itertag一个包含开始迭代的节点名的sring。
namespaces一个由(prefix,url)元组所组成的list。其定义了在该文档中会被spider处理的可用的namespace。prefix及url会被自动调用redister_namespace()生成namespace。可以通过itertag属性中制定节点的namespace。

class YourSpider(XMLFeedSpider):

    namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')]
    itertag = 'n:url'
    # ...

adapt_response(response)该方法在spider分析response前被调用。可以在response被分析前使用该函数来修改内容。
parse_node(response, selector)当节点符合提供的标签名时itertag该方法被调用。接收到的response以及相应的Selector作为参数传递给该方法。该方法返回一个Item对象或者Request对象或者一个包含二者的可迭代对象。
process_results(response, results)当spider返回结果时该方法被调用。设定该方法的目的是在结果返回给框架核心之前作最后的处理。

from scrapy import log
from scrapy.contrib.spiders import XMLFeedSpider
from myproject.items import TestItem

class MySpider(XMLFeedSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/feed.xml']
    iterator = 'iternodes' # This is actually unnecessary, since it's the default value
    itertag = 'item'

    def parse_node(self, response, node):
        log.msg('Hi, this is a <%s> node!: %s' % (self.itertag, ''.join(node.extract())))

        item = TestItem()
        item['id'] = node.xpath('@id').extract()
        item['name'] = node.xpath('name').extract()
        item['description'] = node.xpath('description').extract()
        return item

CSVFeedSpider
用来爬取CSV文件网页

class scrapy.contrib.spiders.CSVFeedSpider

该spider除了其按行遍历而不是节点之外其他和XMLFeedSpider十分类似,而每次迭代时调用的是parse_row().

delimiter在CSV文件中用于区分字段的分隔符。类型为string。默认为’,‘;

headers在CSV文件中包含的用来提取字段的行的列表。
parse_row(response,row)该方法接收一个response对象及一个以提供或检测出来的header为键的字典。该spider中,你可以覆盖adapt_response及process_results方法来进行预处理及后处理。

from scrapy import log
from scrapy.contrib.spiders import CSVFeedSpider
from myproject.items import TestItem

class MySpider(CSVFeedSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/feed.csv']
    delimiter = ';'
    headers = ['id', 'name', 'description']

    def parse_row(self, response, row):
        log.msg('Hi, this is a row!: %r' % row)

        item = TestItem()
        item['id'] = row['id']
        item['name'] = row['name']
        item['description'] = row['description']

SitemapSpider

class scrapy.contrib.spiders.SitemapSpider

SitemapSpider使你爬取网站时可以通过Sitemaps来发现爬取的URL。其支持嵌套的sitemap,并能从robots.txt会获取sitemap的url。

sitemap_urls包含你要爬取的url的sitemap的url列表。也可以指定为一个robots.txt,spider会从中分析并提取url。
sitemap_rules一个包含(regex,callback)元组的列表。

  • regex是一个用于匹配从sitemap提供的url的正则表达式;可以是一个字符串或者编译的正则对象。
  • callback指定了匹配正则表达式的url的处理函数。可以是一个字符串或者callale。规则按顺序进行匹配,之后第一个匹配才会被应用。如果忽略该属性,sitemap中发现的所有url将会被parse函数处理。
  • sitemap_follow一个用于匹配要跟进的sitemap的正则表达式的列表。其仅仅被应用在使用Sitemap index files来指向其他sitemap文件的站点。默认情况下所有的sitemap都回被跟进。
  • sitemap_alternate_links指定当一个url又可选的链接时,是否跟进。有些非英文网站会在一个url块内提供其他语言的网站链接。
<url>
    <loc>http://example.com/</loc>
    <xhtml:link rel="alternate" hreflang="de" href="http://example.com/de"/>
</url>

当 sitemap_alternate_links 设置时,两个URL都会被获取。 当 sitemap_alternate_links 关闭时,只有 http://example.com/ 会被获取。默认 sitemap_alternate_links 关闭。
样例
使用parse处理通过sitemap发现的所有url:

from scrapy.contrib.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/sitemap.xml']

    def parse(self, response):
        pass # ... scrape item here ...

用特定的函数处理某些url,其他的使用另外的callback:

from scrapy.contrib.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/sitemap.xml']
    sitemap_rules = [
        ('/product/', 'parse_product'),
        ('/category/', 'parse_category'),
    ]

    def parse_product(self, response):
        pass # ... scrape product ...

    def parse_category(self, response):
        pass # ... scrape category ...

跟进robots.txt文件定义的sitemap并只跟进包含有..sitemap_shop的url:

from scrapy.contrib.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/robots.txt']
    sitemap_rules = [
        ('/shop/', 'parse_shop'),
    ]
    sitemap_follow = ['/sitemap_shops']

    def parse_shop(self, response):
        pass # ... scrape shop here ...

在SitemapSpider中使用其他url:

from scrapy.contrib.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/robots.txt']
    sitemap_rules = [
        ('/shop/', 'parse_shop'),
    ]

    other_urls = ['http://www.example.com/about']

    def start_requests(self):
        requests = list(super(MySpider, self).start_requests())
        requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls]
        return requests

    def parse_shop(self, response):
        pass # ... scrape shop here ...

    def parse_other(self, response):
        pass # ... scrape other here ...

猜你喜欢

转载自blog.csdn.net/mashaokang1314/article/details/82706804
今日推荐