Scrapy爬虫

爬虫框架

Scrapy简介

Scrapy是一个Python编写的开源网络爬虫框架。它是一个被设计用于爬取网络数据、提取结构性数据的框架

官网:https://scrapy.org/

工作流程

scrapy工作流程

  1. 爬虫中起始的url构造成request对象–>爬虫中间件–>引擎–>调度器
  2. 调度器把request–>引擎–>下载中间件—>下载器
  3. 下载器发送请求,获取response响应—->下载中间件—->引擎—>爬虫中间件—>爬虫
  4. 爬虫提取url地址,组装成request对象—->爬虫中间件—>引擎—>调度器,重复步骤2
  5. 爬虫提取数据—>引擎—>管道处理和保存数据

内置对象模块

  • request请求对象:由url method post_data headers等构成
  • response响应对象:由url body status headers等构成
  • item数据对象:本质是个字

scrapy组件

简单使用

安装:pip install scrapy

创建项目:scrapy startproject 项目名称

scrapy入门使用-1

生成爬虫:进入项目目录执行scrapy genspider 爬虫名称 允许爬取的域名

scrapy入门使用-2

启用管道,修改settings.py

1
2
3
ITEM_PIPELINES = {
'myspider.pipelines.xxxSpider': 400
}

运行爬虫:进入项目目录执行 scrapy crawl itcast

小结

  • scrapy的安装:pip install scrapy
  • 创建scrapy的项目: scrapy startproject myspider
  • 创建scrapy爬虫:在项目目录下执行 scrapy genspider xx xx.cn
  • 运行scrapy爬虫:在项目目录下执行 scrapy crawl xx
  • 解析并获取scrapy爬虫中的数据:
    1. response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
    2. extract() 返回一个包含有字符串的列表
    3. extract_first() 返回列表中的第一个字符串,列表为空没有返回None
  • scrapy管道的基本使用:
    1. 完善pipelines.py中的process_item函数
    2. 在settings.py中设置开启pipeline
  • response响应对象的常用属性
    1. response.url:当前响应的url地址
    2. response.request.url:当前响应对应的请求的url地址
    3. response.headers:响应头
    4. response.requests.headers:当前响应的请求头
    5. response.body:响应体,也就是html代码,byte类型
    6. response.status:响应状态码

管道

管道配置文件是pipelines.py

  1. process_item(self,item,spider):
    • 管道类中必须有的函数
    • 实现对item数据的处理
    • 必须return item
  2. open_spider(self, spider): 在爬虫开启的时候仅执行一次
  3. close_spider(self, spider): 在爬虫关闭的时候仅执行一

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import json
from pymongo import MongoClient

class MyFilePipeline(object):
def open_spider(self, spider): # 在爬虫开启的时候仅执行一次
# 代码逻辑
def close_spider(self, spider): # 在爬虫关闭的时候仅执行一次
# 代码逻辑

def process_item(self, item, spider):
# 代码逻辑
# 不return的情况下,另一个权重较低的pipeline将不会获得item
return item

class MyMongoPipeline(object):
def open_spider(self, spider): # 在爬虫开启的时候仅执行一次
# 代码逻辑

def process_item(self, item, spider):
# 代码逻辑
# 不return的情况下,另一个权重较低的pipeline将不会获得item
return item

开启管道

settings.py设置开启pipeline

1
2
3
4
ITEM_PIPELINES = {
'myspider.pipelines.MyFilePipeline': 400, # 400表示权重
'myspider.pipelines.MyMongoPipeline': 500, # 权重值越小,越优先执行!
}

注意

  1. 使用之前需要在settings中开启
  2. pipeline在setting中键表示位置(即pipeline在项目中的位置可以自定义),值表示距离引擎的远近,越近数据会越先经过:权重值小的优先执行
  3. 有多个pipeline的时候,process_item的方法必须return item,否则后一个pipeline取到的数据为None值
  4. pipeline中process_item的方法必须有,否则item没有办法接受和处理
  5. process_item方法接受item和spider,其中spider表示当前传递item过来的spider
  6. open_spider(spider) :能够在爬虫开启的时候执行一次
  7. close_spider(spider) :能够在爬虫关闭的时候执行一次
  8. 上述俩个方法经常用于爬虫和数据库的交互,在爬虫开启的时候建立和数据库的连接,在爬虫关闭的时候断开和数据库的连接

中间件

根据scrapy运行流程中所在位置不同分为:下载中间件和爬虫中间件,两种中间件都在middlewares.py一个文件中

方法介绍

  • process_request(self, request, spider)

    1. 当每个request通过下载中间件时,该方法被调用。
    2. 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法
    3. 返回Response对象:不再请求,把response返回给引擎
    4. 返回Request对象:把request对象通过引擎交给调度器,此时将不通过其他权重低的process_request方法
  • process_response(self, request, response, spider)

    1. 当下载器完成http请求,传递响应给引擎的时候调用
    2. 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法
    3. 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法

自定义中间件

settings.py中添加

1
2
3
4
5
6
7
8
9
10
USER_AGENTS_LIST = [
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
"Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
"Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
"Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
"Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
]

middlewares.py中添加代码

1
2
3
4
5
6
7
8
9
10
11
12
13
import random
from Tencent.settings import USER_AGENTS_LIST # 注意导入路径,请忽视pycharm的错误提示

class UserAgentMiddleware(object):
def process_request(self, request, spider):
user_agent = random.choice(USER_AGENTS_LIST)
request.headers['User-Agent'] = user_agent
# 不写return

class CheckUA:
def process_response(self,request,response,spider):
print(request.headers['User-Agent'])
return response # 不能少!

settings.py中开启

1
2
3
4
DOWNLOADER_MIDDLEWARES = {
'Test.middlewares.UserAgentMiddleware': 543, # 543是权重值
'Test.middlewares.CheckUA': 600, # 先执行543权重的中间件,再执行600的中间件
}

scrapy_splash

scrapy_splash是scrapy的一个组件

  • scrapy-splash加载js数据是基于Splash来实现的。
  • Splash是一个Javascript渲染服务。它是一个实现了HTTP API的轻量级浏览器,Splash是用Python和Lua语言实现的,基于Twisted和QT等模块构建。
  • 使用scrapy-splash最终拿到的response相当于是在浏览器全部渲染完成以后的网页源代码

docker安装

1
docker run -d -p 8050:8050 scrapinghub/splash

访问 127.0.0.1:8050 查看

python使用

安装:pip install scrapy-splash

1
2
3
4
scrapy startproject test_splash
cd test_splash
scrapy genspider no_splash baidu.com
scrapy genspider with_splash baidu.com

修改settings.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 渲染服务的url
SPLASH_URL = 'http://127.0.0.1:8050'
# 下载器中间件
DOWNLOADER_MIDDLEWARES = {
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
# 去重过滤器
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
# 使用Splash的Http缓存
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import scrapy
from scrapy_splash import SplashRequest # 使用scrapy_splash包提供的request对象

class WithSplashSpider(scrapy.Spider):
name = 'with_splash'
allowed_domains = ['baidu.com']
start_urls = ['https://www.baidu.com/s?wd=13161933309']

def start_requests(self):
yield SplashRequest(self.start_urls[0],
callback=self.parse_splash,
args={'wait': 10}, # 最大超时时间,单位:秒
endpoint='render.html') # 使用splash服务的固定参数

def parse_splash(self, response):
with open('with_splash.html', 'w') as f:
f.write(response.body.decode())

总结

scrapy_splash组件的作用

  1. splash类似selenium,能够像浏览器一样访问请求对象中的url地址
  2. 能够按照该url对应的响应内容依次发送请求
  3. 并将多次请求对应的多次响应内容进行渲染
  4. 最终返回渲染后的response响应对象

scrapy_splash组件的使用

  1. 需要splash服务作为支撑
  2. 构造的request对象变为splash.SplashRequest
  3. 以下载中间件的形式使用
  4. 需要scrapy_splash特定配置

相关文章

Python基础

Python爬虫

Mongodb和Python交互

Python反爬解决方案

Python爬虫

Mongodb和Python交互

Python反爬解决方案

Python打包可执行文件