本篇博客学习使用 CrawlSpider 进行二维抓取。
目标站点分析
本次要采集的目标站点为:阅文集团作家中心
分页地址具备一定规则,具体如下:
https://write.qq.com/portal/article?filterType=0&page={页码}
复制代码
由于本文重点学习内容为简单操作 scrapy
实现爬虫,所以目标详情页仅提取标题即可。
知识说明
本篇博客生成爬虫文件,使用 scrapy genspider -t crawl yw write.qq.com
,默认生成的代码如下所示:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class CbSpider(CrawlSpider):
name = 'yw'
allowed_domains = ['write.qq.com']
start_urls = ['https://write.qq.com/portal/article?filterType=0&page=1']
rules = (
Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
)
def parse_item(self, response):
item = {}
#item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
#item['name'] = response.xpath('//div[@id="name"]').get()
#item['description'] = response.xpath('//div[@id="description"]').get()
return item
复制代码
其中 CrawlSpider
继承自 Spider
,派生该类的原因是为了简化爬取编码,其中增加了类属性 rules
,其值为Rule
对象的集合元组,用于匹配目标网站并排除干扰。
rules = (
Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
)
复制代码
** Rule
类的构造函数原型如下**
Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
复制代码
参数说明如下:
link_extractor
:LinkExtractor 对象,定义了如何从爬取到的页面提取链接;
callback
:回调函数,也可以是回调函数的字符串名。接收 Response 对象作为参数,返回包含 Item 或者 Request 对象列表;
cb_kwargs
:用于作为 **kwargs
参数,传递给 callback
;
follow
:布尔值,默认是 False,用于判断是否继续从该页面提取链接;
process_links
:指定该 spider
中哪个函数将会被调用,从 link_extractor
中获取到链接列表后悔调用该函数,该方法主要用来过滤 url;
process_request
:回调函数,也可以是回调函数的字符串名。用来过滤 Request ,该规则提取到每个 Request 时都会调用该函数。
** LinkExtractor
类构造函数原型如下**
LinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=(), tags=('a', 'area'),
attrs=('href',), canonicalize=False, unique=True, process_value=None, deny_extensions=None,
restrict_css=(), strip=True, restrict_text=None,
)
复制代码
其中比较重要的参数如下所示:
allow
:正则表达式,满足的会被提取,默认为空,表示提取全部超链接;
deny
:正则表达式,不被提取的内容;
allow_domains
:允许的 domains;
deny_domains
:不允许的 domains;
restrict_xpaths
:xpath 表达式
tags
:提取的标签;
attrs
:默认属性值;
restrict_css
:css 表达式提取;
restrict_text
:文本提取。
编码时间
在 rules
变量中,设置两个 URL 提取规则。
# URL 提取规则
rules = (
Rule(LinkExtractor(allow=r'.*/portal/content\?caid=\d+&feedType=2&lcid=\d+$'), callback="parse_item"),
# 寻找下一页 url 地址
Rule(LinkExtractor(restrict_xpaths="//a[@title='下一页']"), follow=True),
)
复制代码
代码重点在寻找下一页部分,使用的是 restrict_xpaths
方法,即基于 xpath 提取,原因是由于使用正则表达式提取下一页地址,写起来略微繁琐。第一个 Rule 规则是获取内容详情页数据,回调函数 callback
是 parse_item
。
完整代码如下所示:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class CbSpider(CrawlSpider):
name = 'yw'
allowed_domains = ['write.qq.com']
start_urls = ['https://write.qq.com/portal/article?filterType=0&page=1']
# URL 提取规则
rules = (
Rule(LinkExtractor(allow=r'.*/portal/content\?caid=\d+&feedType=2&lcid=\d+$'), callback="parse_item"),
# 寻找下一页 url 地址
Rule(LinkExtractor(restrict_xpaths="//a[@title='下一页']"), follow=True),
)
def parse_item(self, response):
print("测试输出")
print(response.url)
title = response.css('title::text').extract()[0]
print(title)
item = {}
# item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
# item['name'] = response.xpath('//div[@id="name"]').get()
# item['description'] = response.xpath('//div[@id="description"]').get()
return item
复制代码
编写完毕,在 settings.py
文件中修改如下内容:
ROBOTSTXT_OBEY = False # 关闭 robots.txt 文件请求
LOG_LEVEL = 'WARNING' # 调高日志输出级别
复制代码
最后得到的结果如下所示。
知识再次补充
在 CrawlSpider
的派生类中,你还可以重写如下方法:
def parse_start_url(self, response):
print("---process_results---")
yield scrapy.Request('https://write.qq.com/portal/article?filterType=0&page=1')
def process_results(self, response, results):
print("---process_results---")
print(results)
def parse_item(self, response):
print("---parse_item---")
print(response.url)
title = response.css('title::text').extract()[0].strip()
item = {}
item["title"] = title
yield item
复制代码
写在后面
今天是持续写作的第 <font color=red>248</font> / 365 天。期待 <font color=#04a9f4>关注</font>,<font color=#04a9f4>点赞</font>、<font color=#04a9f4>评论</font>、<font color=#04a9f4>收藏</font>。
评论