本教程所有源码下载链接:https://share.weiyun.com/5xmFeUO 密码:fzwh6g
Scrapy是一个Python爬虫应用框架,爬取和处理结构性数据非常方便。使用它,只需要定制开发几个模块,就可以轻松实现一个爬虫,让爬取数据信息的工作更加简单高效。
Scrapy使用了Twisted异步网络框架来处理网络通信,可以加快下载速度。结合Scrapy-redis,我们可以实现分布式爬虫,极大地提高了爬虫的效率。试想一下,10台、20台、100台服务器同时爬取数据。。。
Scrapy的安装也非常简单:
pip install scrapy
我们先看一下Scrapy的架构图,来试图理解一下Scrapy的执行流程,然后,带着这些问题,进入Scrapy框架的编写爬虫学习。
这张官方的图解非常形象,但看起来不那么直观,我们来看另一张网友做的图,简单好看,点个赞!
首先,解释一下图中各个组件的作用:
5个组件:
Scrapy Engine
:核心引擎,负责控制和调度各个组件,保证数据流转;
Scheduler
:负责管理任务、过滤任务、输出任务的调度器,存储、去重任务都在此控制;
Downloader
:下载器,负责在网上下载网页数据,输入待下载URL,输出下载结果;
Spiders
:用户自己编写的爬虫脚本,自定义抓取的意图,就是说你需要哪些数据,怎么爬,在这里定义;
Item Pipline
:负责将获取到的数据格式化,格式化、存储、存储位置等在这里质量定义;
2个中间件组件:
Downloader middlewares
:介于引擎和下载器之间,对Scrapy的request/response处理的钩子框架,是用于全局修改Scrapy request和response的一个组件,可以在网页下载前后进行逻辑处理;
Spider middlewares
:介于引擎和爬虫之间,处理引擎发送给Spiders的response,处理spider产生的item和request返回给引擎。
用根据图中的序号,我们用文字来描述一下,Scrapy的运转流程:
start_urls
;构建和运行一个基于Scrapy框架的爬虫的通用步骤如下:
scrapy startproject demoSpider
创建基于Scrapy框架的爬虫项目;scrapy genspider demo demo.com
生成一个基于basic模板的自定义爬虫,爬虫名字为demo;pasrse
方法,编写处理和爬取规则;scrapy crawl demo
执行爬虫。在命令行中创建基于Scrapy框架的爬虫的步骤:
我们在PyCharm中打开创建的项目,项目结构如图:
scrapy.cfg
:项目的主配置文件;demoSpider
:最外层的是项目根目录;第二个是该项目的Python模块;demoSpider/items.py
:项目中item文件,设置数据存储模板,保存爬取到的数据的容器,用于结构化数据,使用方法和字典类似;demoSpider/piplines.py
:项目中的pipelines文件(管道文件),用于数据的持久化处理;demoSpider/middlewares.py
:项目的中间件;demoSpider/settings.py
:项目的设置文件,如,下载延迟、并发数等;demoSpider/spiders/
:编写spider代码的目录。settings.py
文件内容解析刚创建好的demoSpider的settings文件内容是这样的,每个配置项有什么作用,在注释中已经标明了,这里做到心中有数即可,后面实战的时候,会再次使用。
# -*- coding: utf-8 -*-
# 爬虫项目的名字
BOT_NAME = 'demoSpider'
# 爬虫的路径
SPIDER_MODULES = ['demoSpider.spiders']
NEWSPIDER_MODULE = 'demoSpider.spiders'
# 是否遵守爬虫协议
ROBOTSTXT_OBEY = True
# 设置并发请求书,最大是32,默认是16
#CONCURRENT_REQUESTS = 32
# 为同一个网站的请求配置延迟,默认为0;通常用来控制访问爬取频率,防止被识别被禁止。
# 例如设置为0.25,则表示250ms的延迟。
#DOWNLOAD_DELAY = 3
# 每个域名最大并发请求数
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
# 每个ip最大并发请求数,如果设置了,将忽略设置的域名最大并发请求数
#CONCURRENT_REQUESTS_PER_IP = 16
# 是否禁用cookies,默认不禁用
#COOKIES_ENABLED = False
# 通过Telnet可以监听当前爬虫的状态、信息,操作爬虫等。使用方法是:打开cmd,使用telnet 127.0.0.1 6023 以及est(),即可进入操作页面。不常用。
#TELNETCONSOLE_ENABLED = False
# 默认的请求头,每个请求都可以携带。
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# 开始或者禁用中间件,后面的顺序表示优先级,数字越小优先级越高
# 第一个中间件是靠近引擎的中间件,最后一个是靠近蜘蛛的中间件
# 文档 https://doc.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'demoSpider.middlewares.DemospiderSpiderMiddleware': 543,
#}
# 下载中间件,后面的顺序表示优先级,数字越小优先级越高
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
# 'demoSpider.middlewares.DemospiderDownloaderMiddleware': 543,
#}
# 自定义扩展
# See https://doc.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# 自定义PIPELINES处理请求,主要为了存储数据使用,后面的顺序表示优先级,数字越小优先级越高
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
#ITEM_PIPELINES = {
# 'demoSpider.pipelines.DemospiderPipeline': 300,
#}
# 做智能的限速请求。从AUTOTHROTTLE_ENABLED = True开始,到AUTOTHROTTLE_DEBUG = False结束。中间的设置AUTOTHROTTLE_START_DELAY = 5表示第一个请求延迟多少秒。
# 默认禁用。
# See https://doc.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# 起始请求的延迟
#AUTOTHROTTLE_START_DELAY = 5
# 最大的请求延迟
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# 启用后,显示每个响应的控制信息
#AUTOTHROTTLE_DEBUG = False
# 默认禁用,设置HTTP缓存
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
demoSpider/spiders/demo.py
文件内容解析这是一个依据默认模板Scrapy帮我们生成的爬虫,内容简单,由于没有任何自定义的编写,因此,现在还不具备爬虫的功能,我们看一下它的默认内容的使用方法:
# -*- coding: utf-8 -*-
import scrapy
class DemoSpider(scrapy.Spider):
# 爬虫的名字,对应于刚才生成爬虫时指定的名字
name = 'demo'
# 支持的域名,对应于刚才生成爬虫时指定的域名
allowed_domains = ['demo.com']
# 起始链接,爬虫启动后,默认会从这里的url开始发送请求
start_urls = ['http://demo.com/']
# 处理方法,处理引擎转发回来的响应response
def parse(self, response):
pass
parse方法是我们今后处理内容的方法,也就是从response中提取网页的元素或内容。
parse方法的response中,有很多我们可以用的东西:
response.url
:访问的连接;
response.text
:响应的字符串内容;
response.body
:响应的二进制格式内容;
response.meta
:它包含四个信息,如:
{'depth': 1, 'download_timeout': 180.0, 'download_slot': 'dig.chouti.com', 'download_latency': 0.23752975463867188}
demoSpider/items.py
文件内容解析items.py
文件中定义数据存储模板,用面向对象的思维来思考,items中的每个类的实例化对象都是一个包含特定字段和值的结构化数据对象,我们可以将在parse
方法中提取到的数据,保存到这个对象中,然后通过管道文件pipeline
进行后续处理,如保存到文件,或者保存到数据库。
# -*- coding: utf-8 -*-
# 定义数据模板
import scrapy
class DemospiderItem(scrapy.Item):
# 定义字段
# name = scrapy.Field()
pass
例如,假设我们提取了学生信息,有name
、age
、score
等数据,那么我们可以在items.py
中编写一个StudentsItem
类,来存储结构化数据:
import scrapy
class StudentsItem(scrapy.Item):
# 姓名
name = scrapy.Field()
# 年龄
age = scrapy.Field()
# 分数
score = scrapy.Field()
那么,在parse
方法中,提取出来的数据就可以这样存储:
item['name'] = 'zhangsan'
item['age'] = 18
item['score'] = 99
demoSpider/middlewares.py
文件内容解析该文件中包含两个类,分别是DemospiderSpiderMiddleware
爬虫中间件和DemospiderDownloaderMiddleware
下载中间件,如果自定义了它们,那么需要在settings.py
文件中配置它们。在这里,我们不去细致讨论它们,仅需要知道它们在scrapy中的作用即可。关于它们的详解,将在用到的时候进行详细讲解。
demoSpider/pipelines.py
文件内容解析# -*- coding: utf-8 -*-
# 定义item的管道文件
#
# 不要忘记在settings文件的ITEM_PIPELINES中启用它
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
class DemospiderPipeline(object):
# 处理item的方法,该方法必须要返回一个字典数据,Item(或其子类)或者 抛出一个 DropItem 异常。被 drop 的 Item 将不会被接下来的 pipeline 组件处理。
def process_item(self, item, spider):
# raise DropItem()
return item
定义item的管道文件,用来对结构化数据item进行处理,存储到文件或者存储到数据库中。process_item
方法中有两个参数:
item
:爬取的 Item对象;
spider
:爬起item对象的爬虫。
编写好pipelines.py
文件以后,需要在settings.py
文件中启用它:
ITEM_PIPELINES = {
'demoSpider.pipelines.DemospiderPipeline': 300,
}
XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。
XPath基于XML的树状结构,有不同类型的节点,包括元素节点,属性节点和文本节点,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSLT间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。
简单来说,我们通过Xpath可以获取XML中的指定元素和指定节点的值。在网络爬虫中通常会把爬虫获取的HTML数据转换成XML结构,然后通过XPath解析,获取我们想要的结果。
下面,看一下最常用的路径表达式,也是最基础的:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
为了使用方便,我们在Chrome浏览器中安装XPath Helper
插件,帮助我们在页面上测试XPath
表达式。
你可以在Chrome扩展商店中直接搜索下载,由于众所周知的原因,很可能(100%)不能访问,那么可以使用备份下载地址:
安装方法如图所示:
安装完成以后,在Chrome浏览器右上角的扩展插件区域,点击XPath Helper
图标即可激活使用。
这里,我们使用豆瓣电影Top250作为测试页面,同时实战一下XPath Helper
的用法。如图所示:
表达式 | 含义 |
---|---|
//div | 选取页面上全部div元素 |
//div[@class='article'] | 选取页面上属性class的值为article的div元素 |
//div[@class='article']//div[@class='item']//div[@class='hd']//span[@class='title'][1]//text() | 在上面选取的基础上,选取class属性为title的span元素,由于这个span元素有多个,是同一层级下的并列关系,我们只提取第一个,因此需要用[1]获取。text()用来获取文本内容 |
//div[@class='article']//div[@class='item']//div[@class='hd']//a//@href | 获取a标签的属性href的值,也就是电影详细信息页面的URL连接 |
//a[contains(@href,'douban')]//@href | 找到a标签属性href的值中包含douban字符串的a元素,然后取出来href的值 |
//a[starts-with(@href,'https://movie.douban.com')]//@href | 找到a标签属性href的值中以https://movie.douban.com字符串开头的a元素,然后取出来href的值 |
CSS选择器是用来对HTML页面中的元素进行控制的,然后设置属性与值,达到对网页样式就行修饰的目的。
要使用css对HTML页面中的元素实现一对一,一对多或者多对一的控制,这就需要用到CSS选择器。
我们在编写爬虫的过程中,可以使用CSS选择器来对网页上的元素、内容进行定位或者获取。
表达式 | 含义 |
---|---|
* | 选择所有节点 |
#container | 选择id为container的节点 |
.container | 选择所有class包含container的节点 |
li a | 选取所有li 下所有a节点 |
ul + p | 选取ul后面的第一个p元素 |
div#container > ul | 选取id为container的div的第一个ul子元素 |
ul ~p | 选取与ul相邻的所有p元素 |
a[title] | 选取所有有title属性的a元素 |
a[href="http://sunjiajia.com"] | 选取所有href属性为http://sunjiajia.com的a元素 |
a[href*="sunjiajia"] | 选取所有href属性值中包含sunjiajia的a元素 |
a[href^="http"] | 选取所有href属性值中以http开头的a元素 |
a[href$=".jpg"] | 选取所有href属性值中以.jpg结尾的a元素 |
input[type=radio]:checked | 选择选中的radio的元素 |
div:not(#container) | 选取所有id为非container 的div属性 |
li:nth-child(3) | 选取第三个li元素 |
li:nth-child(2n) | 选取第偶数个li元素 |
有关CSS选择器的用法,我们将在实战中进行编写体验。
这章的第1个实战,就是用Scrapy框架重新来爬取豆瓣电影Top250,在这个过程中,熟悉Scrapy框架编写爬虫的基本步骤。
doubanSpider
Scrapy项目:
scrapy startproject doubanSpider douban
:
scrapy genspider douban douban.com settings.py
中,将ROBOTSTXT_OBEY = True
改为ROBOTSTXT_OBEY = False
;
settings.py
中,配置User-Agent:
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' items.py
文件,定义我们需要的:
import scrapy class DoubanspiderItem(scrapy.Item): # 标题 title = scrapy.Field() # 信息 bd = scrapy.Field() # 评分 star = scrapy.Field() # 简介 quote = scrapy.Field() spiders/douban.py
爬虫文件:
# -*- coding: utf-8 -*- import scrapy from doubanSpider.items import DoubanspiderItem class DoubanSpider(scrapy.Spider): name = 'douban' allowed_domains = ['douban.com'] # 基础url地址 url = "https://movie.douban.com/top250?start=" # url参数 offset = 0 # 起始url列表 start_urls = [ url + str(offset) ] def parse(self, response): item = DoubanspiderItem() # 拿到 movies = response.xpath('//div[@class="info"]') for each in movies: # 标题 item['title'] = each.xpath( './/div[@class="hd"]//span[@class="title"][1]/text()').extract()[0] # 信息 item['bd'] = each.xpath( './/div[@class="bd"]/p/text()').extract()[0].strip() # 评分 item['star'] = each.xpath( './/div[@class="star"]/span[@class = "rating_num"]/text()').extract()[0] # 简介 quote = each.xpath('.//div[@class="bd"]//p[@class="quote"]/span/text()').extract() if len(quote) != 0: item['quote'] = quote[0] # 交给管道文件处理 yield item # 循环发送请求,读取每一页的内容 if self.offset < 225: self.offset += 25 yield scrapy.Request(self.url + str(self.offset), callback=self.parse) pipelines.py
管道文件,用来数据持久化处理:
import json class DoubanspiderPipeline(object): def __init__(self): """ 构造方法,在这里打开文件 """ self.item_list = [] self.filename = open("douban.json", "w+") def process_item(self, item, spider): """ 处理item数据 """ item_json = json.dumps(dict(item), ensure_ascii=False) self.item_list.append(item_json) return item def close_spider(self, spider): """ 爬虫关闭时执行,对数据进行最后的修正工作,并且关闭文件输入输出流 """ content = "[" + ",".join(self.item_list) + "]" self.filename.write(content) self.filename.close() settings.py
文件中,配置管道文件:
ITEM_PIPELINES = { 'doubanSpider.pipelines.DoubanspiderPipeline': 300, } 要求:
parse()
方法中用XPath
表达式提取数据的方式,修改为CSS选择器
方式提取;扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有