一:入门
-
scrapy startproject tutorial
创建新的爬虫项目 -
scrapy crawl quotes
运行名为quotes的爬虫
示例代码:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').extract_first(),
'author': quote.css('small.author::text').extract_first(),
'tags': quote.css('div.tags a.tag::text').extract(),
}
- 运行流程简述
- Scrapy为Spider的
start_urls
属性中的每个URL创建了scrapy.Request
对象,并将parse
方法作为回调函数(callback)赋值给了Request。 - Request对象经过调度,执行生成
scrapy.http.Response
方法。
- Scrapy为Spider的
-
Scrap结构
- Engine:引擎负责控制系统所有组件之间的数据流,并在发生某些操作时触发事件。
- Downloader:下载器负责提取网页并将它们馈送到引擎,然后引擎将其发送给Spiders
- Spiders:Spiders是Scrapy用户编写的自定义类,用于解析响应并从中提取item项目(也称为抓取的项目)或追加的其他请求。
- Item Pipeline:Item Pipeline负责处理被蜘蛛提取的item, 典型的任务包括清理,验证和持久性(如将项目存储在数据库中)
- Downloader middlewares:下载器中间件是位于引擎和下载器之间的特定的钩子,当它们从引擎传递到下载器时处理请求,以及从下载器传递到引擎的响应
- Scheduler:调度程序接收来自引擎的请求,并将它们排入队列,并在之后,当Engine需要的时候,将requests发送给engine。
二:
命令行工具
- Scrapy是通过 scrapy 命令行工具进行控制的
命令行工具(Command line tools)
可用的工具命令(tool commands)
Items
爬取的主要目标就是从非结构性的数据源提取结构性数据,Scrapy提供Item
对象保存了爬取到得数据。
定义Item
import scrapy
Item使用简单的class定义语法以及 `Field`
class Product(scrapy.Item):
name = scrapy.Field() [`Field`]对象指明了每个字段的元数据(metadata)
price = scrapy.Field()
stock = scrapy.Field()
last_updated = scrapy.Field(serializer=str)
Item字段
使用Item
from tutorial.items import DmozItem
class DmozSpider(scrapy.Spider):
name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
]
def parse(self, response):
for sel in response.xpath('//ul/li'):
item = DmozItem()
item['title'] = sel.xpath('a/text()').extract()
item['link'] = sel.xpath('a/@href').extract()
item['desc'] = sel.xpath('text()').extract()
yield item
Spiders
Spider类定义了如何爬取某个网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item).
对spider来说,爬取的循环类似下文:
以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。
spider中初始的request是通过调用start_requests()
来获取的。start_requests()
读取start_urls
中的URL, 并以parse
为回调函数生成Request
。在回调函数内分析返回的(网页)内容,返回
Item
对象或者Request
或者一个包括二者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。
最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。
虽然该循环对任何类型的spider都(多少)适用,但Scrapy仍然为了不同的需求提供了多种默认spider。
最常用的Spider:CrawlSpider
除了从Spider继承过来的(您必须提供的)属性外,其提供了一个新的属性:rules(爬取规则)
该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(该spider中同名的函数将会被调用)。 从link_extractor中每获取到链接时将会调用该函数。
- 其余参数参看官方文档
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
选择器
当抓取网页时,最常见的任务是从HTML源码中提取数据,Scrapy提取数据有自己的一套机制。它们被称作选择器(seletors),因为他们通过特定的 XPath 或者 CSS 表达式来“选择” HTML文件中的某个部分。
实例:
>>> from scrapy import Selector
>>> doc = """
... <div>
... <ul>
... <li class="item-0"><a href="link1.html">first item</a></li>
... <li class="item-1"><a href="link2.html">second item</a></li>
... <li class="item-inactive"><a href="link3.html">third item</a></li>
... <li class="item-1"><a href="link4.html">fourth item</a></li>
... <li class="item-0"><a href="link5.html">fifth item</a></li>
... </ul>
... </div>
... """
>>> sel = Selector(text=doc, type="html")
>>> sel.xpath('//li//@href').extract()
[u'link1.html', u'link2.html', u'link3.html', u'link4.html', u'link5.html']
>>> sel.xpath('//li[re:test(@class, "item-\d$")]//@href').extract()
[u'link1.html', u'link2.html', u'link4.html', u'link5.html']
>>>
Item Loaders
Item Loaders提供了一种便捷的方式填充抓取到的 Items
。 虽然Items可以使用自带的类字典形式API填充,但是Items Loaders提供了更便捷的API, 可以分析原始数据并对Item进行赋值