在之前的文章中我们介绍了 scrapy 框架并给予 scrapy 框架写了一个爬虫来爬取《糗事百科》的糗事,本章我们继续说一下 scrapy 框架并对之前的糗百爬虫做一下优化和丰富。

在上一篇文章中,我们在项目中创建了一个 qiushiSpider.py 的文件,代码如下:

 import scrapy
from ..items import QiushiItem class QiushiSpider(scrapy.Spider):
# 爬虫名
name = "qiubai"
# 允许爬虫作用的范围,不能越界
allowd_domains = ["https://www.qiushibaike.com/"]
# 爬虫起始url
start_urls = ["https://www.qiushibaike.com/text/page/1/"] # 我们无需再像之前利用 urllib 库那样去请求地址返回数据,在 scrapy 框架中直接利用下面的 parse 方法进行数据处理即可。
def parse(self, response):
# 通过 scrayy 自带的 xpath 匹配想要的信息
qiushi_list = response.xpath('//div[contains(@id,"qiushi_tag")]')
for site in qiushi_list:
# 实例化从 items.py 导入的 QiushiItem 类
item = QiushiItem()
# 根据查询发现匿名用户和非匿名用户的标签不一样
try:
# 非匿名用户
username = site.xpath('./div/a/img/@alt')[0].extract() # 作者
imgUrl = site.xpath('./div/a/img/@src')[0].extract() # 头像
except Exception:
# 匿名用户
username = site.xpath('./div/span/img/@alt')[0].extract() # 作者
imgUrl = site.xpath('./div/span/img/@src')[0].extract() # 头像
content = site.xpath('.//div[@class="content"]/span[1]/text()').extract()
item['username'] = username
item['imgUrl'] = "https:" + imgUrl
item['content'] = content
yield item

在上面的代码中我们定义了一个 QiubaiSpider 的类,并且集成了 scrapy.Spider,我们就对这个类做一下详细分析。

Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。

 class scrapy.Spider 是最基本的类,所有编写的爬虫必须继承这个类。

主要用到的函数及调用顺序为:

__init__()  初始化爬虫名字和start_urls列表

start_requests() 调用 make_requests_from url() 生成Requests对象交给Scrapy下载并返回response

parse() 解析response,并返回Item或Requests(需指定回调函数)。Item传给Item pipline持久化 , 而Requests交由Scrapy下载,并由指定的回调函数处理(默认parse() ),一直进行循环,直到处理完所有的数据为止。

 #所有爬虫的基类,用户定义的爬虫必须从这个类继承
class Spider(object_ref): #定义spider名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。
#name是spider最重要的属性,而且是必须的。
#一般做法是以该网站(domain)(加或不加 后缀 )来命名spider。 例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite
name = None #初始化,提取爬虫名字,start_ruls
def __init__(self, name=None, **kwargs):
if name is not None:
self.name = name
# 如果爬虫没有名字,中断后续操作则报错
elif not getattr(self, 'name', None):
raise ValueError("%s must have a name" % type(self).__name__) # python 对象或类型通过内置成员__dict__来存储成员信息
self.__dict__.update(kwargs) #URL列表。当没有指定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。
if not hasattr(self, 'start_urls'):
self.start_urls = [] # 打印Scrapy执行后的log信息
def log(self, message, level=log.DEBUG, **kw):
log.msg(message, spider=self, level=level, **kw) # 判断对象object的属性是否存在,不存在做断言处理
def set_crawler(self, crawler):
assert not hasattr(self, '_crawler'), "Spider already bounded to %s" % crawler
self._crawler = crawler @property
def crawler(self):
assert hasattr(self, '_crawler'), "Spider not bounded to any crawler"
return self._crawler @property
def settings(self):
return self.crawler.settings #该方法将读取start_urls内的地址,并为每一个地址生成一个Request对象,交给Scrapy下载并返回Response
#该方法仅调用一次
def start_requests(self):
for url in self.start_urls:
yield self.make_requests_from_url(url) #start_requests()中调用,实际生成Request的函数。
#Request对象默认的回调函数为parse(),提交的方式为get
def make_requests_from_url(self, url):
return Request(url, dont_filter=True) #默认的Request对象回调函数,处理返回的response。
#生成Item或者Request对象。用户必须实现这个类
def parse(self, response):
raise NotImplementedError @classmethod
def handles_request(cls, request):
return url_is_from_spider(request.url, cls) def __str__(self):
return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self)) __repr__ = __str__

主要属性和方法

  • name

    定义spider名字的字符串。

    例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite

  • allowed_domains

    包含了spider允许爬取的域名(domain)的列表,可选。

  • start_urls

    初始URL元祖/列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。

  • start_requests(self)

    该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取(默认实现是使用 start_urls 的url)的第一个Request。

    当spider启动爬取并且未指定start_urls时,该方法被调用。

  • parse(self, response)

    当请求url返回网页没有指定回调函数时,默认的Request对象回调函数。用来处理网页返回的response,以及生成Item或者Request对象。

  • log(self, message[, level, component])

    使用 scrapy.log.msg() 方法记录(log)message。

接下来我们再将之前的的糗百爬虫进行一下丰富。之前的爬虫,我们只是爬取了第一页内糗事,即  start_urls = ["https://www.qiushibaike.com/text/page/1/"] ,其中最末尾的 1 即代表了当前页码,所以当该页数据爬取完毕后让其自动 +1 即为下一页内容,然后再接着爬取我们想要的数据。

 import scrapy
from ..items import QiushiItem
import re class QiushiSpider(scrapy.Spider):
# 爬虫名
name = "qiubai"
# 允许爬虫作用的范围,不能越界
allowd_domains = ["https://www.qiushibaike.com/"]
# 爬虫起始url
start_urls = ["https://www.qiushibaike.com/text/page/1/"] # 我们无需再像之前利用 urllib 库那样去请求地址返回数据,在 scrapy 框架中直接利用下面的 parse 方法进行数据处理即可。
def parse(self, response):
# 通过 scrayy 自带的 xpath 匹配想要的信息
qiushi_list = response.xpath('//div[contains(@id,"qiushi_tag")]')
for site in qiushi_list:
# 实例化从 items.py 导入的 QiushiItem 类
item = QiushiItem()
# 根据查询发现匿名用户和非匿名用户的标签不一样
try:
# 非匿名用户
username = site.xpath('./div/a/img/@alt')[0].extract() # 作者
imgUrl = site.xpath('./div/a/img/@src')[0].extract() # 头像
except Exception:
# 匿名用户
username = site.xpath('./div/span/img/@alt')[0].extract() # 作者
imgUrl = site.xpath('./div/span/img/@src')[0].extract() # 头像
content = site.xpath('.//div[@class="content"]/span[1]/text()').extract()
item['username'] = username
item['imgUrl'] = "https:" + imgUrl
item['content'] = content # 通过 re 模块匹配到请求的 url 里的数字
currentPage = re.search('(\d+)', response.url).group(1)
page = int(currentPage) + 1
url = re.sub('\d+', str(page), response.url) # 将获取的数据交给 pipeline
yield item # 发送新的 url 请求加入待爬队列,并调用回调函数 self.parse
yield scrapy.Request(url, callback=self.parse)

在上面的代码中,我们在将获取到的 item 数据交给管道文件 pipeline 之后,获取到此时的请求 url 链接,根据 re 模块获取到链接里的数字,即页码数,然后将页码数 +1,再次发送新的 url 链接请求即可获取其余页码的数据了。

Python 爬虫从入门到进阶之路(十七)的更多相关文章

  1. Python 爬虫从入门到进阶之路(八)

    在之前的文章中我们介绍了一下 requests 模块,今天我们再来看一下 Python 爬虫中的正则表达的使用和 re 模块. 实际上爬虫一共就四个主要步骤: 明确目标 (要知道你准备在哪个范围或者网 ...

  2. Python 爬虫从入门到进阶之路(二)

    上一篇文章我们对爬虫有了一个初步认识,本篇文章我们开始学习 Python 爬虫实例. 在 Python 中有很多库可以用来抓取网页,其中内置了 urllib 模块,该模块就能实现我们基本的网页爬取. ...

  3. Python 爬虫从入门到进阶之路(六)

    在之前的文章中我们介绍了一下 opener 应用中的 ProxyHandler 处理器(代理设置),本篇文章我们再来看一下 opener 中的 Cookie 的使用. Cookie 是指某些网站服务器 ...

  4. Python 爬虫从入门到进阶之路(九)

    之前的文章我们介绍了一下 Python 中的正则表达式和与爬虫正则相关的 re 模块,本章我们就利用正则表达式和 re 模块来做一个案例,爬取<糗事百科>的糗事并存储到本地. 我们要爬取的 ...

  5. Python 爬虫从入门到进阶之路(十二)

    之前的文章我们介绍了 re 模块和 lxml 模块来做爬虫,本章我们再来看一个 bs4 模块来做爬虫. 和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也 ...

  6. Python 爬虫从入门到进阶之路(十五)

    之前的文章我们介绍了一下 Python 的 json 模块,本章我们就介绍一下之前根据 Xpath 模块做的爬取<糗事百科>的糗事进行丰富和完善. 在 Xpath 模块的爬取糗百的案例中我 ...

  7. Python 爬虫从入门到进阶之路(十六)

    之前的文章我们介绍了几种可以爬取网站信息的模块,并根据这些模块爬取了<糗事百科>的糗百内容,本章我们来看一下用于专门爬取网站信息的框架 Scrapy. Scrapy是用纯Python实现一 ...

  8. Python 爬虫从入门到进阶之路(五)

    在之前的文章中我们带入了 opener 方法,接下来我们看一下 opener 应用中的 ProxyHandler 处理器(代理设置). 使用代理IP,这是爬虫/反爬虫的第二大招,通常也是最好用的. 很 ...

  9. Python 爬虫从入门到进阶之路(七)

    在之前的文章中我们一直用到的库是 urllib.request,该库已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 “HTTP for Hum ...

随机推荐

  1. 在WPF里面实现以鼠标位置为中心缩放移动图片

    原文:在WPF里面实现以鼠标位置为中心缩放移动图片 在以前的文章使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果里面,介绍了如何在WPF里面移动和放大缩小图片, ...

  2. WPF 4 开发Windows 7 跳转列表(JumpList)

    原文:WPF 4 开发Windows 7 跳转列表(JumpList)      在之前写过的<Windows 7 任务栏开发系列>中我们通过Visual Studio 2008 借助微软 ...

  3. Ogre 1.7.0,VS2005编译全过程傻瓜式教程

    最近下了最新版Ogre 1.7.0,从下载到最后编译运行成功Ogre自带的Sample花了将近一下午时间. 网上有很多编译Ogre的教程,这里整理我看过的教程,加上自己的经验再详细总结一遍. 第一步: ...

  4. 【全面解禁!真正的Expression Blend实战开发技巧】十一章 全面解析布局(Grid & Canvas &StackPanel &Wrappanel)

    原文:[全面解禁!真正的Expression Blend实战开发技巧]十一章 全面解析布局(Grid & Canvas &StackPanel &Wrappanel) 写这篇文 ...

  5. uwp 获取系统字体库

    原文:uwp 获取系统字体库 效果图: 要获取到字体库首先要在 NuGet 添加 SharpDx.Direct2D1  api: /// <summary> /// 获取系统字体库列表 / ...

  6. iis7下查看站点日志对应文件夹

    原文:iis7下查看站点日志对应文件夹 IIS7下面默认日志文件的存放路径:%SystemDrive%\inetpub\logs\LogFiles 查看方法:点击对应网站 -> 右侧功能视图 - ...

  7. 规则“Microsoft Visual Studio 2008 的早期版本”失败。此计算机上安装了 Microsoft Visual Studio 2008 的早期版本。请在安装 SQL Server 2008 前将 Microsoft Visual Studio 2008 升级到 SP1。

    今天重装了一下系统后,需要装开发工具,我用的开发工具是Visual Studio2008 和SQL Server2008R2,装完Visual Studio2008的时候在装数据库的时候却出现这样的问 ...

  8. no identifier specified for entity错误

    未给entity类添加主键造成. 之前出现这个错误是因为忘记给id添加@Id标签.

  9. Windows实用小工具-问题步骤记录器

    今晚给大家介绍个实用的好工具,可以做简单的问题记录,再也不用截图加注释这么辛苦了····· 经测试,这东东在win7,2008 及2008R2里适用,也就是说,在win7以上的系统中才有.好了,下面直 ...

  10. ORA-09925: Unable to create audit trail file

    当我修改ORACLE_SID为新的SID,想进行数据库还原时,用sqlplus报如下错误 [oracle@dbtest ~]$ sqlplus / as sysdba SQL Production : ...