Scrapy一个开源和协做的框架,其最初是为了页面抓取所设计的,使用它能够以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分普遍,可用于如数据挖掘、监测和自动化测试等领域,也能够应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。css
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。所以Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。总体架构大体以下html
执行流程:node
1.引擎从spider获取初始爬行请求。2.引擎在调度程序中调度请求,并请求下一个要爬行的请求。3.调度程序将下一个请求返回到引擎。4.引擎将请求发送到下载器,并经过下载器中间件(请参见process_request())。5.一旦页面完成下载,下载器将生成响应(使用该页面),并将其发送到引擎,并经过下载器中间软件(请参见process_response())。6.引擎接收下载器的响应并将其发送给spider进行处理,并经过spider中间件进行处理(请参见process_spider_input())。7.spider处理响应,并经过spider中间件(请参见process_spider_output())向引擎返回刮掉的项目和新请求(后续)。8.引擎将已处理的项目发送到项目管道,而后将已处理的请求发送到计划程序,并请求可能的下一个请求进行爬网。9.该过程重复(从步骤1开始),直到调度程序再也不发出请求。python
引擎(EGINE)git
引擎负责控制系统全部组件之间的数据流,并在某些动做发生时触发事件。有关详细信息,请参见上面的数据流部分。github
调度器(SCHEDULER)用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 能够想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址web
下载器(DOWLOADER)用于下载网页内容, 并将网页内容返回给EGINE,下载器是创建在twisted这个高效的异步模型上的ajax
爬虫(SPIDERS)SPIDERS是开发人员自定义的类,用来解析responses,而且提取items,或者发送新的请求sql
项目管道(ITEM PIPLINES)在items被提取后负责处理它们,主要包括清理、验证、持久化(好比存到数据库)等操做shell
下载器中间件(Downloader Middlewares)
位于Scrapy引擎和下载器之间,主要用来处理从EGINE传到DOWLOADER的请求request,已经从DOWNLOADER传到EGINE的响应response
爬虫中间件(Spider Middlewares)位于EGINE和SPIDERS之间,主要工做是处理SPIDERS的输入(即responses)和输出(即requests
#Windows平台
1、pip3 install wheel #安装后,便支持经过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs
3、pip3 install lxml
4、pip3 install pyopenssl
5、下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/
6、下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
7、执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
8、pip3 install scrapy
#Linux平台
1、pip3 install scrapy
#1 查看帮助
scrapy -h
scrapy <command> -h
#2 有两种命令:其中Project-only必须切到项目文件夹下才能执行,而Global的命令则不须要
Global commands:
startproject #建立项目
scrapy startproject amazon
genspider #建立爬虫程序 指定名称 限制爬取的网址
scrapy genspider amzon www.amzon.cn
settings #若是是在项目目录下,则获得的是该项目的配置
scrapy settings --get BOT_NAME
runspider #运行一个独立的python文件,没必要建立项目
scrapy runspider amzon.py
shell #scrapy shell url地址 在交互式调试,如选择器规则正确与否
scrapy shell www.taobao.com
fetch #单纯地爬取一个页面,不打开浏览器,能够拿到请求头
scrapy fetch --nolog http://www.baidu.com 不输出日志
scrapy fetch --nolog --header http://www.baidu.com 不输出日志 只查看头信息
view #下载完毕后直接弹出浏览器,以此能够分辨出哪些数据是ajax请求
scrapy view http://www.baidu.com
version #scrapy version 查看scrapy的版本,scrapy version -v查看scrapy依赖库的版本
scrapy version -v
Project-only commands:
#必须先切换到对应的目录才能执行
crawl #运行爬虫,必须建立项目才行,确保配置文件中ROBOTSTXT_OBEY = False
scrapy crawl amzon
check #检测项目中有无语法错误
scrapy check
list #列出项目中所包含的爬虫名
scrapy list
edit #编辑器,通常不用
parse #scrapy parse url地址 --callback 回调函数 #以此能够验证咱们的回调函数是否正确
bench #scrapy bentch压力测试
#3 官网连接
https://docs.scrapy.org/en/latest/topics/commands.html
project_name/
scrapy.cfg
project_name/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
爬虫1.py
爬虫2.py
爬虫3.py
文件说明:
scrapy.cfg 项目的主配置信息,用来部署scrapy时使用,爬虫相关的配置信息在settings.py文件中。
items.py 设置数据存储模板,用于结构化数据,如:Django的Model
pipelines 数据处理行为,如:通常结构化的数据持久化
settings.py 配置文件,如:递归的层数、并发数,延迟下载等。强调:配置文件的选项必须大写不然视为无效,正确写法USER_AGENT='xxxx'
spiders 爬虫目录,如:建立文件,编写爬虫规则
注意:通常建立爬虫文件时,以网站域名命名
import sys,os
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')
在项目目录下新建:entrypoint.py
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', 'amzon'])
一、Spiders是由一系列类(定义了一个网址或一组网址将被爬取)组成,具体包括如何执行爬取任务而且如何从页面中提取结构化的数据。
二、换句话说,Spiders是你为了一个特定的网址或一组网址自定义爬取和解析页面行为的地方
#一、生成初始的Requests来爬取第一个URLS,而且标识一个回调函数
第一个请求定义在start_requests()方法内默认从start_urls列表中得到url地址来生成Request请求,默认的回调函数是parse方法。回调函数在下载完成返回response时自动触发
#二、在回调函数中,解析response而且返回值
返回值能够4种:
包含解析数据的字典
Item对象
新的Request对象(新的Requests也须要指定一个回调函数)
或者是可迭代对象(包含Items或Request)
#三、在回调函数中解析页面内容
一般使用Scrapy自带的Selectors,但很明显你也可使用Beutifulsoup,lxml或其余你爱用啥用啥。
#四、最后,针对返回的Items对象将会被持久化到数据库
经过Item Pipeline组件存到数据库:https://docs.scrapy.org/en/latest/topics/item-pipeline.html#topics-item-pipeline)
或者导出到不一样的文件(经过Feed exports:https://docs.scrapy.org/en/latest/topics/feed-exports.html#topics-feed-exports)
Spider 基础的爬虫 也是咱们呢最经常使用的爬虫 不会对response 进行任何解析 直接传给回调函数
SitemapSpider 站点信息爬虫 对于须要seo优化的网站一般会在网站根目录下建立 站点地图文件
其中列出网站全部连接地址,而后将该文件提交给搜索引擎,搜索引擎收录后,会查看其中的信息,例如最后跟新时间等,以便于搜索引擎的爬虫更有效的爬取你的网页
CrawlSpider
CrawlSpider类定义了一些规则(rule)来提供跟进link的机制,从爬取的网页中获取link并继续爬取。
固定格式爬虫
CSVFeedSpider 回调函数parse_row包含一个row用于直接提取一行内容
XMLFeedSpider,回调函数parse_node包含一个node表示一个节点
这是最简单的spider类,任何其余的spider类都须要继承它(包含你本身定义的)。
该类不提供任何特殊的功能,它仅提供了一个默认的start_requests方法默认从start_urls中读取url地址发送requests请求,而且默认parse做为回调函数
class AmazonSpider(scrapy.Spider):
name = 'amazon'
allowed_domains = ['www.amazon.cn']
start_urls = ['http://www.amazon.cn/']
custom_settings = {
'BOT_NAME' : 'Egon_Spider_Amazon',
'REQUEST_HEADERS' : {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
}
def parse(self, response):
pass
#一、name = 'amazon'
定义爬虫名,scrapy会根据该值定位爬虫程序
因此它必需要有且必须惟一(In Python 2 this must be ASCII only.)
#二、allowed_domains = ['www.amazon.cn']
定义容许爬取的域名,若是OffsiteMiddleware启动(默认就启动),
那么不属于该列表的域名及其子域名都不容许爬取
若是爬取的网址为:https://www.example.com/1.html,那就添加'example.com'到列表.
#三、start_urls = ['http://www.amazon.cn/']
若是没有指定start_requests,就从该列表中读取url来生成第一个请求
#四、custom_settings
值为一个字典,定义一些配置信息,在运行爬虫程序时,这些配置会覆盖项目级别的配置
因此custom_settings必须被定义成一个类属性
#五、settings
经过self.settings['配置项的名字']能够访问settings.py中的配置,若是本身定义了custom_settings仍是以本身的为准
#六、logger
日志名默认为spider的名字
self.logger.debug('=============>%s' %self.settings['BOT_NAME'])
#七、start_requests()
该方法用来发起第一个Requests请求,且必须返回一个可迭代的对象。它在爬虫程序打开时就被Scrapy调用,Scrapy只调用它一次。
默认从start_urls里取出每一个url来生成Request(url, dont_filter=True)
#八、parse(response)
这是默认的回调函数,全部的回调函数必须返回an iterable of Request and/or dicts or Item objects.
#九、closed(reason)
爬虫程序结束时自动触发
在爬取网页的过程当中可能会爬到一些重复的网页,这就须要制定去重规则了,默认状况下scrapy就会自动帮咱们去除
去重规则应该多个爬虫共享的,但凡一个爬虫爬取了,其余都不要爬了,实现方式以下
#方法一:
1、新增类属性
visited=set() #类属性
2、回调函数parse方法内:
def parse(self, response):
if response.url in self.visited:
return None
.......
self.visited.add(response.url)
#方法一改进:针对url可能过长,因此咱们存放url的hash值
def parse(self, response):
url=md5(response.request.url)
if url in self.visited:
return None
.......
self.visited.add(url)
#方法二:Scrapy自带去重功能
配置文件:
DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter' #默认的去重规则帮咱们去重,去重规则在内存中
DUPEFILTER_DEBUG = False # 是否记录全部重复请求 默认为第一个重复请求
JOBDIR = "保存范文记录的日志路径,如:/root/" # 最终路径为 /root/requests.seen,去重规则放文件中
scrapy自带去重规则默认为RFPDupeFilter,只须要咱们指定
Request(...,dont_filter=False) ,若是dont_filter=True则告诉Scrapy这个URL不参与去重。
#方法三:
咱们也能够仿照RFPDupeFilter自定义去重规则,
from scrapy.dupefilter import RFPDupeFilter,看源码,仿照BaseDupeFilter
#步骤一:在项目目录下自定义去重文件dup.py
class UrlFilter(object):
def __init__(self):
self.visited = set() #或者放到数据库
response经常使用属性与方法
text 获取文本
body 获取二进制
css() css选择器
xpath() xptah解析
css与xpath返回值都是selector类型
selector经常使用方法
extract 提取字符串形式数据
extract_first 提取第一个
css() 在当前文档上继续查找其余元素 返回selector类型
xpath()在当前文档上继续查找其余元素 返回selector类型
https://www.cnblogs.com/kermitjam/
scrapy中使用item来做为数据模型,pipeline做为数据持久化组件
找到items文件 为itme类添加所需的属性
class PicItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
url = scrapy.Field()
一个pipeline应该具有如下几个方法
class MyPipeline():
def process_item(self, item, spider):
"""
负责将一个Item进行持久化
返回值将继续传递给下一个pipeline(若是有),即使是None
"""
return item
def open_spider(self, spider):
"""
爬虫程序启动时执行该函数
用于初始化操做例如链接数据库
"""
pass
def close_spider(self, spider):
"""
爬虫程序关闭时执行该函数
用于初清理操做例如关闭数据库
"""
pass
# 建立pipeline 会自动查看是否存在该方法若是存在则直接调用 用于获取一个pipline
# crawler中的settings属性能够获取配置文件信息
#数字表示优先级,数值越小优先级越高
ITEM_PIPELINES = {
"name.pipelines.MysqlPipeline":10,
"name.pipelines.JsonPipeline":20
}
class JsonPipeline():
def __init__(self):
self.json_data = []
# 在这里处理item的持久化
def process_item(self, item, spider):
self.json_data.append(dict(item))
return item
def open_spider(self, spider):
pass
def close_spider(self, spider):
with open("pics.json","wt") as f:
json.dump(self.json_data,f)
process_item函数一旦有返回值就会继续执行后续的pipeline,即时返回None,能够是使用如下方法中断
#导入 DropItem类
from scrapy.exceptions import DropItem
# 在process_item中抛出异常
def process_item(self, item, spider):
raise DropItem
下载器主要负责从网络上下载数据,下载器中间件用于对请求与响应进行处理
例如:设置cookie,header,添加代理等等
class DownMiddleware1(object):
def process_request(self, request, spider):
"""
该方法在下载器发起请求前执行
:param request:
:param spider:
:return:
None,继续后续中间件去下载;
Response对象,中止process_request的执行,开始执行process_response
Request对象,中止中间件的执行,将Request从新调度器
raise IgnoreRequest异常,中止process_request的执行,开始执行process_exception
"""
pass
def process_response(self, request, response, spider):
"""
数据下载完成,返回spider前执行
:param response:
:param result:
:param spider:
:return:
Response 对象:转交给其余中间件process_response
Request 对象:中止中间件,request会被从新调度下载
raise IgnoreRequest 异常:调用Request.errback
"""
print('response1')
return response
def process_exception(self, request, exception, spider):
"""
当下载处理器(download handler)或 process_request() (下载中间件)抛出异常时执行
:param response:
:param exception:
:param spider:
:return:
None:继续交给后续中间件处理异常;
Response对象:中止后续process_exception方法
Request对象:中止中间件,request将会被从新调用下载
"""
return None
DOWNLOADER_MIDDLEWARES = {
'name.middlewares.TDownloaderMiddleware': 100,
}
须要注意的是优先级必定要比系统的高,由于scrapy本身有个proxy中间件
首先须要明确代理池的原理,从网页上爬取免费的代理地址数据,在请求时,若是对方服务器,限制访问IP,就从代理池中获取代理地址从新访问
网络上有不少线程的开源代理池,这里以IPProxyPool 为例
下载地址:https://github.com/qiyeboy/IPProxyPool
1.下载代理池
2.安装依赖
在代代理池目录中找到requirements.txt 复制其路径 执行如下命令
pip3 install -r 文件路径
3.下载webpy https://codeload.github.com/webpy/webpy/zip/py3
安装webpy
切换目录到webpy文件夹中执行如下命令
python setup.py install
4.运行IPProxy.py文件开始爬取ip
执行过程可能报错,根据错误信息安装对应的模块便可
5.在项目中请求代理池的接口获取代理ip
import requests,random
ips = None
def get_proxy():
global ips
if not ips:
ips = requests.get("http://127.0.0.1:8001/").json()
a = random.choice(ips)
return "http://"+a[0]+":"+str(a[1])
def delete_ip(ip):
ip = ip.strip("http://").split(":")[0]
res = requests.get("http://127.0.0.1:8001/delete?ip="+ip).json()
print(res)
if __name__ == '__main__':
# print(get_proxy())
#delete_ip("http://60.184.34.232:9999")
使用scrapy 编写爬虫项目的步骤
1.使用scrapy startproject 项目名称
2.cd到spiders文件夹下
3.scrapy genspider jd www.jd.com
不能加http
4.在spider中 使用start_request()函数来指定爬虫爬去=取的页面
5.在回调函数中解析数据 默认回调parse
能够返回一个item 也能够返回request
若是是item 调用pipeline进行数据持久化
若是是request则继续发起请求
6.定义items来描述数据 item 其实就是数据模型Model
7.在pipeline中 编写相应额持久化代码
open_spider 作初始化操做 例如 连接数据库
close_spider 作清理操做 例如关闭数据库
process_item 具体的持久化逻辑
8.可选的下载器中间件 一般用于设置 代理 header cookie
1.编写一个中间件类
2.在配置文件中注册中间件
9.爬虫中间件 ,使用场景较少 了解便可