第1章 初识scrapy
1.1 创建第一个项目
- 项目描述:
抓取电商网站上的图书名称和价格
地址:http://books.toscrape.com/catalogue/page-1.html
- 流程:
新建项目 —— 新建爬虫 —— 修改爬虫 ——运行爬虫并保存
# 1.新建项目
scrapy startproject example
# 2.新建爬虫
scrapy genspider book_spider
# 3.修改爬虫
# 解析网页
for book in response.css('article.product_pod'):
name = book.xpath('./h3/a/@title').extract_first()
price = book.css('p.price_color::text').extract_first()
yield {'name':name, 'pirce':price}
# 实现翻页
next_url = response.css('ul.pager li.next a::attr(href)').extract_first()
if next_url:
next_url = response.urljoin(next_url)
yield scrapy.Request(next_url, callback=self.parse)
# 4.运行并保存
scrapy crawl book_spider -o books.csv
第2章 编写spider
2.1 request 对象
- Request对象用来描述一个HTTP请求,下面是其构造器方法的参数列表:
scrapy.request( )
的参数
详情参见:https://blog.csdn.net/weixin_37947156/article/details/74974208
官方文档:https://doc.scrapy.org/en/latest/topics/request-response.html
Request(url,
callback,
headers,
body, meta, priority=0, errback)
2.2 response 对象
- 当一个页面下载完成时,下载器依据HTTP响应头部中的Content-Type信息创建某个Response的子类对象。
- 下面介绍HtmlResponse对象的常用属性,前两个方法用于提取数据,后一个方法用于构造绝对url。
xpath(query)
:使用XPath选择器在Response中提取数据,实际上它是response.selector.xpath方法的快捷方式css(query)
:使用CSS选择器在Response中提取数据,实际上它是response.selector.css方法的快捷方式urljoin(url)
:用于构造绝对url。当传入的url参数是一个相对地址时,根据response.url计算出相应的绝对url。
例如,response.url为http://www.example.com/a,url为b/index.html,调用response.urljoin(url)的结果为 http://www.example.com/a/b/index.html。
- 其他参数详情参见:书《精通Scrapy网络爬虫框架》P16
2.3 spider开发流程
Scrapy框架提出以下问题让用户在Spider子类中作答
- 爬虫从哪个或哪些页面开始爬取?
- 对于一个已下载的页面,提取其中的哪些数据?
- 爬取完当前页面后,接下来爬取哪个或哪些页面?
为爬虫设置其实爬取地址的方式
- 定义start_urls属性
- 实现start_requests方法
第三章 使用selector提取数据
3.1 selector对象
提取数据的方法:
调用Selector或SelectorLis对象的以下方法可将选中的内容提取:- extract()
- re()
- extract_first() (SelectorList专有)
- re_first() (SelectorList专有)
3.2 Response内置selector
页面解析测试
from scrapy.http import HtmlResponse
response = HtmlResponse(url='http://www.example.com', body=body, encoding='utf8')
response.selector
3.3 XPath
XPath即XML路径语言(XML Path Language),它是一种用来确定xml文档中某部分位置的语言。
xml文档的节点有多种类型,其中最常用的有以下几种:
- 根节点 整个文档树的根。
- 元素节点 html、body、div、p、a。
- 属性节点 href。
- 文本节点 Hello world、Click here。
节点间的关系有以下几种:
- 父子 body是html的子节点,p和a是div的子节点。反过来,div是p和a的父节点。
- 兄弟 p和a为兄弟节点。
- 祖先/后裔 body、div、p、a都是html的后裔节点;反过来html是body、div、p、a的祖先节点。
第四章 使用Item封装数据
4.1 Item和Field(利用BookItem代替字典)
- Item基类
自定义数据类(如BookItem)的基类。 - Field类
用来描述自定义数据类包含哪些字段(如name、price等)。
>>> from scrapy import Item, Field
>>> class BookItem(Item):
... name = Field()
... price = Field()
# Item支持字典接口,因此BookItem在使用上和Python字典类似,可按以下方式创建BookItem对象:
# 方法一:
>>> book1 = BookItem(name='Needful Things', price=45.0)
>>> book1
{'name': 'Needful Things', 'price': 45.0}
# 方法二:
>>> book2 = BookItem()
>>> book2
{}
>>> book2['name'] = 'Life of Pi'
>>> book2['price'] = 32.5
{'name': 'Life of Pi', 'price': 32.5}
3.修改之前的BooksSpider,使用BookItem替代Python字典,代码如下:
from ..items import BookItem
class BooksSpider(scrapy.Spider):
...
def parse(self, response):
for sel in response.css('article.product_pod'):
book = BookItem()
book['name'] = sel.xpath('./h3/a/@title').extract_first()
book['price'] = sel.css('p.price_color::text').extract_first()
yield book
...
4.2 拓展Item子类
- 新建一个ForeignBookItem类,增添一个译者字段,其他的继承BookItem类,代码如下:
>>> class ForeignBookItem(BookItem):
... translator = Field()
...
>>> book = ForeignBookItem()
>>> book['name'] = '巴黎圣母院'
>>> book['price'] = 20.0
>>> book['translator'] = '陈敬容'
4.3 Field元数据
- field()的元数据可以是列表、字符串或者函数
class BookItem(Item):
...
authors = Field(serializer=lambda x: '|'.join(x))
...
第五章 使用Item Pipeline处理数据
- 以下是Item Pipeline的几种典型应用:
- 清洗数据
- 验证数据的有效性
- 过滤掉重复的数据
- 将数据存入数据库
5.1 Item Pipeline
5.1.1 实现Item Pipeline
- item pipeline常用方法:
- process_item(item, spider):处理数据
- open_spider(self, spider):打开
Spider打开时(处理数据前)回调该方法,通常该方法用于在开始处理数据之前完成某些初始化工作,如连接数据库。 - close_spider(self, spider):关闭
Spider关闭时(处理数据后)回调该方法,通常该方法用于在处理完所有数据之后完成某些清理工作,如关闭数据库。 - from_crawler(cls, crawler):调回
创建Item Pipeline对象时回调该类方法。通常,在该方法中通过crawler.settings读取配置,根据配置创建Item Pipeline对象。
5.1.2 启用Item Pipeline
- 想要启用某个(或某些)Item Pipeline,需要在配置文件settings.py中进行配置:
ITEM_PIPELINES = {
'example.pipelines.PriceConverterPipeline': 300,
}