Python:Scrapy(一) 基础知识与实例
学习自:
Scrapy爬虫框架教程(一)-- Scrapy入门 - 知乎
Scrapy爬虫框架,入门案例(非常详细)_ck784101777的博客-CSDN博客_scrapy爬虫案例
本章介绍Scrapy使用时的基本要素构成。
1、简介
Scrapy最初是为了页面抓取/网络抓取设计的。Scrapy用途广泛,可以应用数据挖掘、监控、自动化测试等领域。
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便地进行修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
2、各组件作用
Scrapy框架主要由五大组件组成,分别是Scrapy引擎(Scrapy Engine)、下载器(Downloader)、Spider、Item Pipeline、调度器(Scheduler)。
①Scrapy Engine
引擎是整个框架的核心,它用来控制、调度Scheduler、Downloader、Spider。
②调度器(Scheduler)
调度器可以视为一个想要进行抓取的URL队列,由它来决定下一个要抓取的网址是什么,同时可以去除重复的网址。用户可以根据自己的需求定制调度器。
③下载器(Downloader)
下载器负责下载页面数据并提供给引擎,而后提供给Spider。Scrapy的下载器代码并不复杂,但是效率很高,这是因为Scrapy下载器是建立在twisted这个高效的异步模型上的。
④Item Pipeline
Item Pipeline负责处理被Spider提取出来的Item。典型的处理有清理多余信息、验证Item有效性及持久化Item(例如存取到数据库中)。
当页面被爬虫解析所需的数据存入Item之后,将会被发送到Pipeline,并经过几个特定的次序处理数据,最后存入本地文件或者存入数据库。
⑤Spider
用户定制自己的爬虫(通过正则表达式等语法),用于从特定的网页中提取自己需要的信息,即Item。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面。
除了以上五种组件,还有另外三个概念(它们与前边五种组件是相互关联的)也需要了解:
①下载器中间件(Downloader middlewares)
下载器中间件是在引擎及下载器之间的特定钩子(Specific hook),处理Downloader传递给引擎的response。它提供了一个简便机制,通过插入自定义代码来扩展Scrapy功能
通过设置下载器中间件可以事先爬虫自动更换User-Agent、IP等功能。
②Spider中间件(Spider middlewares)
Spider中间件是在引擎及Spider之间的特定钩子(Specific hook),处理Spider的输入(Response)和输出(Item及Requests)。
③数据流(Data Flow)
1).Engine打开一个网站,找到处理该网站的Spider并向该Spider请求第一个要爬取的URL(s);
2).Engine从Spider中获取到第一个要爬取的URL,将其放入Scheduler的URL队列中;
3).Engine向Scheduler请求下一个要爬取的URL;
4).Scheduler返回下一个要爬取的URL给Engine,Engine将URL发送给Downloader;
5)、6).Downloader访问Internet,下载页面;
7).Downloader生成一个该页面的Response,并将其发送给Engine;
8).Engine将Response发送给Spider处理;
9).Spider处理Response并返回爬取到的Item及新URL给Engine,重复上述流程直到URL队列中没有多余URL;
10).Engine将爬取到的Item发送到Item Pipeline。
将整个流程可视化,可以得到如下流程图,该图是按照上文数据流中的顺序进行的。
官方架构图:图中的绿线是数据流向。
3、一些类、文件的作用
①类
1)Spider
class scrapy.spider.Spider
Spider是最简单的spider。每个其他的spider都必须继承自该类(包括Scrapy自带的其他spider以及我们自己编写的spider)。Spider没有提供其他特殊的功能,其作用为1)区分请求给定的start_urls/start_requests;2)根据response调用parse方法。
属性:
name:spider名字的字符串。spider的名字定义了Scrapy如何开始定位(并初始化)spider,所以其必须是唯一的。如果该spider爬取单个网站,一个常见的做法是以该网站名来命名spider。例如spider要爬取mywebsite.com,该spider通常会被命名为mywebsite。
allowed_domains:可选。包含了spider允许爬取的URL List。当OffsiteMiddleware启用时,不在List中指定URL及其子URL中的URL将不会被跟进(即爬取的URL必须与该List中的URL有相同的前缀)。
start_urls:URL List。当没有特定的URL时,spider将从该List中开始进行爬取。因此,第一个被获取到的页面的URL必将是该List其中之一,后续URL将会从获取到的数据中提取。
方法:
start_requests():该方法必须返回一个Iterable。该Iterable包含了spider用于爬取的第一个Request。当spider启动爬取且并未制定URL时,该方法将会被调用。该方法的默认实现是使用start_urls的URL来生成Request。如果我们想要修改最初爬取某个网站的Request对象,那么可以重写该方法。例如,如果我们需要在启动时以POST的方式登录某个网站,可以这么写
def start_requests(self):
return [scrapy.FormRequest('http://www.example.com/login',
formdata={'user': 'john', 'pass': 'secret'},
callback=self.logged_in)]
def logged_in(self,response):
pass
默认未被重写的情况下,该方法返回的Request对象中,parse()作为回调函数,dont_filter参数也被设置为开启。(详情见Reueqst)
make_requests_from_url(url):当spider启动且指定了URL时,该方法将会被调用,且仅仅会被调用一次,因此我们可以将之实现为Generator。该方法接受一个URL并返回用于爬取的Request对象。该方法在初始化Requests时被start_requests调用,也被用于转化URL为Request。
parse(response):当Response没有指定回调函数时,该方法是Scrapy处理下载的Response的默认方法。该方法负责处理Response并返回处理的数据以及跟进的URL。spider对其他的Request的回调函数也有相同的要求。关于返回值,该方法及其他Request回调函数必须返回一个包含Request或Item的Iterable。
参数:response:用于分析的Response
log(message [ ,level , commponent ] ):使用scrapy.log.msg()方法记录(log)message。log中自动带上该spider的name属性。更多数据可以参见Logging。
closed(reason):当spider关闭时,该方法被调用。该方法用于替代signals.connect()来监听spider_closed信号的快捷方式。
以上是最简单的Spider,此外还有其他Spider:Spiders — Scrapy 2.5.0 documentation
2)CrawlSpider
用于爬取URL具有一定规律的网页
3)Response
Scrapy中的response对象的属性、方法
属性 | 说明 | 类型 |
url | HTTP响应的URL | str |
status | 响应状态码 | int |
headers | 响应头部,可以用get或getlist方法访问 | 类Dict |
body | 响应正文 | bytes |
text |
文本形式的响应正文 response.text = response.body.decode(response.encoding) |
str |
encoding | 响应正文的编码 | |
request | 产生该响应的Request对象 | |
meta | 即response.request.meta,在构造Request对象时,可以将传递给响应处理函函数的信息通过meta参数传入;响应处理函数处理相应时,通过response.meta将信息提取出来 | |
selector | Selector对象用于在Response中提取数据 |
方法 | 说明 |
xpath(query) | 根据XPath路径表达式提取要素 |
css(query) | 根据CSS语法提取要素 |
urljoin(url) | 用于构造绝对url,当传入的url是一个相对地址时,根据response.url计算出相应的绝对url |
②文件
通过指令scrapy startproject S创建项目后,会生成以下的文件结构:
S--->scrapy.cfg #项目的配置文件
S--------> #该项目的Python模块。之后你将在此加入代码
__init__.py
items.py #项目中的Item文件
pipelines.py #Pipelines文件
settings.py #设置文件
spiders---> #放置Spider代码的目录
__init__.py
xxx.py #Spider代码
除了目录名S和Spider文件名是我们自定义的外,其他文件都是自动生成的,其中最关键的是pipelines.py和settings.py
1)items.py
存放需要提取元素名。
2)settings.py
BOT_NAME:项目名。
USER_AGENT:该项默认是注释掉的,但是由于现在的网站访问时都需要User-Agent,所以需要我们手动填充该项。
ROBOTSTXT_OBEY:是否遵循机器人协议,默认True,需要修改为False,否则很多东西爬不了(该项待验证)。
CONCURRENT_REQUESTS:最大并发数;同时允许开启多少个爬虫线程。
DOWNLOAD_DELAY:下载延迟时间;单位s,默认3s,即爬一个停3s。有的网站可能会对下载过快的情况进行侦测,从而判断出是爬虫并加以拒绝。
COOKIES_ENABLED:是否保存COOKIES;默认关,开启后可以记录爬取过程中的COOKIE。
DEFAULT_REQUEST_HEADERS:默认请求头;之前我们写了一个USER_AGENT,其实该项就是放在请求头中的。
ITEM_PIPELINES:项目管道;300为优先级,越低爬取的优先级越高。比如我的pipelines.py中写了两个pipeline,一个爬取网页的管道,另一个存数据库的管道,我调整了它们的优先级,如果有爬虫数据,则优先执行库存操作(如果items.py中有需要运行的代码,则该项必须声明)
ITEM_PIPELINES = {
'S.pipelines.BaiduPipeline' : 300,
'S.pipelines.BaiduMysqlPipeline':200
}
该Dict中的两个Key需要均是在要在pipelines.py事先定义好的两个类:
class BaiduPipeline(object):
#爬取网页
def process_item(self,item,spider):
return item class BaiduMysqlPipeline(object):
#将爬取内容存入数据库
def process_item(self,item,spider):
return item
LOG_LEVEL:日志等级;日志登记分级见下表
DEBUG | 调试信息 |
INFO | 一般信息 |
WARNING | 警告 |
ERROR | 普通错误 |
CRITICAL | 严重错误 |
默认为'DEBUG',即所有信息都会被记录进日志中,如果设置为WARNING,则只会记录WARNING、ERROR和CRITICAL
LOG_FILE:日志文件名;格式为 '日志名.log'
3.5、建立Scrapy爬虫项目的流程
创建爬虫和运行爬虫时,要在cmd中用到三段指令:
scrapy startproject 项目名
scrapy genspider 爬虫名 域名
scrapy crawl 爬虫名
其中前两句分别是创建项目和创建爬虫,而创建爬虫也可以通过第②部分中的中的name和start_urls进行创建。
第三句话是爬虫构建好之后,运行爬虫的命令。
①创建项目
在开始爬取之前,需要建立一个新的Scrapy项目。
进入你打算存储代码的目录中,运行以下命令
scrapy startproject 项目名
cd 项目名
scrapy genspider 爬虫名 URL
②编写爬虫代码
Spider是用户编写的用于从网站爬取数据的类。
其包含了一个用于下载初始URL,如何跟进网页中的链接及如何分析页面中的内容,提取生成Item的方法。
为了创建一个Spider,你必须继承scrapy.Spider类,且定义以下三个属性及方法
name:用于区别不同的Spider。
start_urls:包含了Spider在启动时进行爬取的URL列表。因此,第一个被获取到的页面将是其中之一。后续的URL则从初始URL获取到的数据中心提取。
parse():Spider的一个方法。被调用时,每个初始URL完成下载后生成的Response对象将作为唯一的参数传递给该函数。该方法负责解析返回的数据(response data),提取数据(生成Item)以及生成需要进一步处理的URL的Request对象。
③启动爬虫
打开终端进入项目所在文件夹中,运行命令:
scrapy crawl woodenrobo
启动爬虫后就可以看到打印出来当前页所有的文章标题了。
可以把爬取到的内容导出为JSON或者CSV格式,方法是在执行爬虫指令时加入参数-o:
scrapy crawl 爬虫名 -o 文件名.csv
scrapy crawl 爬虫名 -o 文件名.json
对于JSON文件,需要在setting.py文件中设置编码格式,否则会乱码:
FEED_EXPORT_ENCODING = 'UTF-8'
启动爬虫时的程序运行流程:
Scrapy为Spider的start_urls属性中的每个URL创建了Request对象,并将parse方法作为回调函数赋值给requests,而requests对象经过Scheduler的调度,执行生成response对象并送回给parse()方法进行解析,所以url的改变是靠回调函数实现的。
yield scrapy.Request(self.url,callback=self.parse)
4、实例
①提取百度首页的标题title
现在看第一个Spider代码,保存位置为S2\Spiders目录下,名字取为baidu.py,目的是使用XPath提取百度首页的标题title
import scrapy class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['www.baidu.com']
start_urls = ['http://www.baidu.com/'] def parse(self, response):
tile=response.xpath('//html/head/title/text()')
print(tile)
打开cmd终端,输入
scrapy crawl baidu
就可以看到一大堆输出信息,其中就包含了我们需要的内容。
然而,使用终端运行太麻烦了,而且不能提取数据,我们写一个运行文件作为程序的入口:
from scrapy import cmdline cmdline.execute('scrapy crawl baidu'.split())
这段话可以写在另一个py文件或者spider.py文件中,直接运行这句话所在的py文件就可以了。
②爬取腾讯视频中的电影信息
1)
创建项目,将爬虫项目命名为TX;
创建爬虫,爬虫命名为txms,爬虫的start_url设置为v.qq.com
scrapy startproject TX
cd TX
scrapy genspider txs v.qq.com
2)修改setting
修改三项:
ROBOTSTXT_OBEY:机器人项
DOWNLOAD_DELAY:下载间隙
DEFAULT_REQUEST_HEADERS:请求头,需要添加一个User-Agent
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 1
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36'
}
3)确认要提取的数据,Item项
Item定义你要提取的内容(定义数据结构),比如我提取的内容为电影名和电影描述,我就创建两个变量(每有一个需要提取的内容,就要在items.py中新建一个变量)。Field方法实际上是创建一个Dict,给Dict添加一个Key,暂时不赋值,等待提取数据后再赋值。
下面的Item结构可以表示为:{ 'name':'' ; 'description':'' }
#items.py import scrapy class TXItem(scrapy.Item):
name=scrapy.Field()
description=scrapy.Field()
4)写爬虫程序
我们要写的部分是parse方法中的内容,重点在于如何写XPath。
我们要爬取的网页的URL为https://v.qq.com/channel/movie,页面如下:
from scrapy import Request
from scrapy import Spider
from TX.items import TXItem class TxsSpider(Spider):
name = 'txs'
allowed_domains = ['v.qq.com']
start_urls = ['https://v.qq.com/channel/movie'] def parse(self, response):
item=TXItem()
movies=response.xpath('//div[@id="movie_v3_new"]//div[@class="list_item "]')
for movie in movies:
item['name']=movie.xpath('.//div/a/text()').extract()[0]
item['description']=movie.xpath('.//div/div/text()').extract()[0]
yield item
5)、运行爬虫,保存爬取到的数据
scrapy crawl tms -o TX.csv
这一部分代码的解释,请看Scrapy(二)最后一部分
Python:Scrapy(一) 基础知识与实例的更多相关文章
- Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现
Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现 一丶进程基础知识 什么是程序: 程序就是一堆文件 什么是进程: 进程就是一个正在 ...
- Python开发(一):Python介绍与基础知识
Python开发(一):Python介绍与基础知识 本次内容 一:Python介绍: 二:Python是一门什么语言 三:Python:安装 四:第一个程序 “Hello world” 五:Pytho ...
- 基于Python的Flask基础知识
Flask简介 Flask 是一个使用 Python 编写的轻量级 Web 应用程序框架.Armin Ronacher带领一个名为Pocco的国际Python爱好者团队开发了Flask. 下面我们简单 ...
- Python第一章-基础知识
第一章:基础知识 1.1 安装python. 直接官网下载最新的python然后默认安装就可以了,然后开始菜单里找到pyhton *.*.* Shell.exe运行python的交互shell ...
- Python音频处理基础知识,这不是轻轻松松~~~
大家好鸭,我是小熊猫 咱今天来讲一讲音频处理的基础知识上才艺~~~ 1.声音的基础 2.python读取.wav音频 欢迎加入白嫖Q群:660193417### import wave import ...
- python这不是有手就行?——python音频处理基础知识
大家应该都知道声音的基础吧? 啊不知道当我没说吧~~~ 1.声音的基础 2.python读取.wav音频 Python学习交流Q群:660193417#### import wave import s ...
- Python之进程 基础知识 上
阅读目录 理论知识 操作系统背景知识 什么是进程 进程调度 进程的并发与并行 同步\异步\阻塞\非阻塞 进程的创建与结束 在python程序中的进程操作 multiprocess模块 进程的创建和mu ...
- Python程序设计1——基础知识
1 Python脚本设计简介 1.1 输出"Hello World" 和一般的语言一样,运行python程序有两种方式,一种是GUI交互式命令,一种是通过脚本文件,前者适合小型简单 ...
- Python开发——1.基础知识
一.开发 开发语言分为高级语言和低级语言 高级语言:Python.Java.PHP.C++.C#.GO.Ruby等:低级语言:C.汇编语言. 高级语言对应的是字节码,是将代码编译成字节码,然后交给机器 ...
随机推荐
- Kubernetes 微服务最佳实践
本文由个人笔记 ryan4yin/knowledge 整理而来 本文主要介绍我个人在使用 Kubernetes 的过程中,总结出的一套「Kubernetes 配置」,是我个人的「最佳实践」. 其中大部 ...
- Kubernetes常见的部署方案(十四)
一.常见的部署方案 滚动更新 服务不会停止,但是整个pod会有新旧并存的情况. 重新创建 先停止旧的pod,然后再创建新的pod,这个过程服务是会间断的. 蓝绿 (无需停机,风险较小) 部署v1的应用 ...
- Elasticsearch (1) 文档操作
本文介绍如何在Elasticsearch中对文档进行操作. 1.检查Elasticsearch及Kibana运行是否正常 在浏览器输入192.168.6.16:9200,有如下输出则说明Elastic ...
- 「YNOI2016」自己的发明
「YNOI2016」自己的发明 不换根 基本的莫队吧... 子树直接转到dfs序上. 其余部分可以见 「SNOI2017」一个简单的询问. 换根 根root,查询x,分3种: root不在x子树内,按 ...
- 关于CALayer的疑惑
- 有了Autolayout的UILabel
在没有Autolayout之前,UILabel的文字内容总是居中显示,导致顶部和底部会有一大片空缺区域 有Autolayout之后,UILabel的bounds默认会自动包住所有的文字内容,顶部和底部 ...
- js 数组map用法 Array.prototype.map()
map 这里的map不是"地图"的意思,而是指"映射".[].map(); 基本用法跟forEach方法类似: array.map(callback,[ thi ...
- js实现网页中英文翻译
1,html 2,metrics.js 3,需要 http://www.microsoftTranslator.com/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKk ...
- JMeter使用流程
JMeter使用流程 首先我们要新建一个线程组,线程组的作用模拟多个访问对象,对系统可以进行压力测试 添加"HTTP Cookie管理器": 添加"Http请求默认值&q ...
- HTTP缓存小结
介绍 提到页面优化,浏览器缓存必定是一个绕不过的话题,判断一个网站的性能最直观的就是看网页打开的速度,而提高网页反应速度的一个方式就是使用缓存.一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟, ...