scrapy分页抓取网页(用Scrapy写爬虫再只要理清下面两点就能写成一个 )
优采云 发布时间: 2021-11-15 04:04scrapy分页抓取网页(用Scrapy写爬虫再只要理清下面两点就能写成一个
)
1 简介
Scrapy模块中有4个现成的蜘蛛类,分别是:
SpiderCrawlSpiderXMLFeedSpiderCSVFeedSpider
Spider是最简单的爬虫,也是最基本的爬虫。包括自定义爬虫在内的所有其他爬虫都必须继承它。本节主要讲Scrapy编写爬虫的核心内容,从CrawlSpider类开始,开始学习如何搭建最简单的爬虫程序。
在我写的第一篇文章中,我说爬虫无非是以下几点:
请求(requests)目标站点的网页(文本);使用正则表达式、Beautiful Soup、LXML、CSS 提取数据;制定爬取规则(如“下一页”等)、爬取方式(异步爬取、设置代理等);存储数据。
至于如何存储数据,我们暂时不关心,因为在Scrapy的命令行中,可以通过参数直接将数据存储到文件中,见【命令行工具】-命令行工具。
总结我以往的经验,用Scrapy写爬虫,只要搞清楚以下两点就可以写成爬虫了:
知道要爬哪些页面,爬完这个页面后要爬哪些页面,入口点在哪里;如何从这些页面中提取数据
对于第二点,我们在最近的3次文章中已经做了详细的介绍。这里我就不多说了。学习完本节内容后,您可以进一步了解提取数据的方法:
[Easy XPath]-开始使用XPath
[RegEx]-正则表达式
【Scrapy中的选择器】-数据匹配方法
因此,本节将带您从示例中阐明编写爬虫的思路和方法。
2 需求分析
假设你目前不清楚如何用Scrapy写爬虫,那么你手头只有一个任务,就是你要爬取哪些数据网站。所以第一步就是分析需求,搞清楚爬取的顺序,其他的就别管了。
任务:
爬取->网站 热门标签下的所有引用及其作者
看看这个页面:
scrapy view http://quotes.toscrape.com/
图片右侧的红框是热门标签。让我们随机点击一个标签来签到:
http://quotes.toscrape.com/tag/love/
我们将上图定义为标签主页,上图中的红框代表我们需要提取的数据项。在数据爬取中,我们必须最大程度的保证数据的完整性,也就是说:获取所有存在于网站上的目标数据。除了标签首页的数据,剩下的数据在哪里?入口在哪里?
往下我们找到Next按钮,打开调试器查看它的地址:
http://quotes.toscrape.com/tag/love/page/2/
点击第二页,已经找不到Next按钮了,也就是love标签下的数据只存在于两个页面:
http://quotes.toscrape.com/tag/love/
http://quotes.toscrape.com/tag/love/page/2/
总结两个步骤:
① 获取首页右侧所有热门标签对应的地址:
http://quotes.toscrape.com/tag/love/
http://quotes.toscrape.com/tag/inspirational/
……
② 访问各标签首页,在各标签首页点击“下一步”获取剩余数据,直到找不到下一步按钮
最后再补充一点:
爱标签首页的数据,分析起来,是第一页。这是否意味着它相当于:
http://quotes.toscrape.com/tag/love/page/1/
我们在标签主页上找到了这个链接:
因此,可以按以下顺序获取每个标签下的数据:
http://quotes.toscrape.com/tag/love/page/1/
http://quotes.toscrape.com/tag/love/page/2/
……
这是第一点:
下面两个网站指向同一个页面:
http://quotes.toscrape.com/tag/love/
http://quotes.toscrape.com/tag/love/page/1/
如果我们按照上面的页数抓取数据,那么我们的数据就是重复的。我们需要在下面进一步解决这个问题。
3 CrawlSpider类使用详解
先通风一下它独特的属性和方法,然后就从刚刚完成上述任务开始,给爬虫代码,写下CrawlSpider类中各个参数用法的例子。
① parse_start_url(response)
用于处理start_urls的响应,它的用处是:如果需要模拟登录等操作,可以重写这个方法。
② Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
规则用于:
以指定格式提取链接(link_extractor);过滤提取的链接(process_links);为指定页面指定相应的处理方法(process_request);指定页面的处理方式(回调);为不同的提取链接方法指定后续规则(Follow);将参数 (cb_kwargs) 传递给回调函数。
避免使用 parse 作为回调函数(callback)
在 PyCharm 中创建文件如下:
env:虚拟环境
simple:爬虫文件夹
Quotes_CrawlSpider.py:爬虫
run.py:用于启动爬虫,方便调试
run.py的代码如下:
from scrapy import cmdline
cmdline.execute("scrapy runspider Quotes_CrawlSpider.py -o quotes.json".split())
解释:
相当于从命令行启动爬虫文件,-oquotes.json将爬虫产生的item保存到json文件中。
3.1 完成上述爬虫任务所需的爬虫代码
Quotes_CrawlSpider.py 的代码如下:
# -*- coding: utf-8 -*-
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
class MySpider(CrawlSpider):
name = 'toscrape.com'
allowed_domains = ['toscrape.com']
start_urls = ['http://quotes.toscrape.com/']
rules = (
Rule(LinkExtractor(allow=('/tag/\w+/$',)),
follow=True, # 如果有指定回调函数,默认不跟进
callback='parse_item',
process_links='process_links',),
Rule(LinkExtractor(allow=('/tag/\w+/page/\d+/',), deny=('/tag/\w+/page/1/',)),
callback='parse_item',
follow=True,),
)
@staticmethod
def process_links(links): # 对提取到的链接进行处理
for link in links:
link.url = link.url + 'page/1/'
yield link
@staticmethod
def parse_item(response): # 解析网页数据并返回数据字典
quote_block = response.css('div.quote')
for quote in quote_block:
text = quote.css('span.text::text').extract_first()
author = quote.xpath('span/small/text()').extract_first()
item = dict(text=text, author=author)
yield item
流程图:
详细代码:
提取规则1:(①-④)
Rule(LinkExtractor(allow=('/tag/\w+/$',)), # 从主页提取标签主页的地址,利用正则表达式
follow=True, # request标签主页得到内容,继续在该内容上上应用规则提取链接
callback='parse_item', # request标签主页得到内容,对该内容应用parse_item函数提取数据
process_links='process_links',), # 用process_links方法对提取到的链接做处理,将标签主页变成/page/1/形式
提取规则2:(⑤,⑥)
Rule(LinkExtractor(allow=('/tag/\w+/page/\d+/',), deny=('/tag/\w+/page/1/',)),
# 提取链接格式满足“/tag/英文字母/page/”数字/形式的,并拒绝第一页
callback='parse_item', # 指定parse_item作为页面的处理方法
follow=True,), # 需要在得到的页面继续搜索满足规则的链接
parse_start_url(响应)
from scrapy.spiders import CrawlSpider
class QuotesSpider(CrawlSpider):
name = "quotes"
custom_settings = {
'LOG_LEVEL': 'INFO',
}
start_urls = ['http://quotes.toscrape.com/tag/love/']
def parse_start_url(self, response):
self.logger.info('parse_start_url %s', response.url)
next_page = response.css('li.next a::attr("href")').extract_first()
if next_page is not None:
yield response.follow(next_page, self.next_parse)
def next_parse(self, response):
self.logger.info('next_pares %s', response.url)
rule的几个参数用法示例:
# -*- coding: utf-8 -*-
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
class MySpider(CrawlSpider):
name = 'toscrape.com'
custom_settings = {
'LOG_LEVEL': 'INFO', # 设置日志级别
}
allowed_domains = ['toscrape.com']
start_urls = ['http://quotes.toscrape.com/']
rules = (
Rule(LinkExtractor(allow=('/tag/\w+/$',)),
follow=False, # 为了测试几个参数的用法简单设定
callback='parse_item',
cb_kwargs={'tag': 'love'}, # 以key名tag作为变量名传给回调函数parse_item
process_links='process_links', # 对提取的链接做处理
process_request='process_req' # 对每个请求做处理),
)
@staticmethod
def process_links(links):
for link in links:
link.url = link.url + 'page/1/'
yield link
def process_req(self, req):
if 'love' in req.url: # 我们测试当链接中包含love是转给parse_love处理response
return req.replace(callback=self.parse_love)
elif 'humor' in req.url:
return req # 如果链接中包含humor则正常用回调函数parse_item处理response
def parse_love(self, response):
self.logger.info('parse_love %s' % response.url)
def parse_item(self, response, tag):
self.logger.info('parse_item %s' % response.url)
self.logger.info('not %s' % tag)
操作结果:
操作流程: