安装scrapy:
1.pip3 install wheel
2.下载twisted 网址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 如下图
3.cmd进入你所下载文件的目录,pip3 install 你下的文件名
4.pip3 install pywin32
5.pip3 install scrapy
大功告成!!!
创建scrapy项目
# 1. 在终端敲入命令:scrapy startproject 项目名
# 2. cd 进你所创建的项目中 (这样第三步所创建的文件会自动加入进项目中的spider目录中)
# 3. 创建爬虫文件:scrapt genspider 文件名 url
# 文件内容
import scrapy
class FirstSpider(scrapy.Spider):
# 爬虫文件的名称:根据名称可以定位到指定的爬虫文件
name = 'first'
# 允许的域名
# allowed_domains = ['www.baidu.com'] # 一般会将其注释
# 起始的url列表
start_urls = ['https://www.baidu.com/'] # 创建文件时所写的起始url
def parse(self, response):
print(response)
# 4. 运行文件:scrapy crawl 文件名 【--nolog】不写时运行会出现log日志
第一次运行scrapy问题
# 第一次运行如果写了 --nolog不会出现结果
# 问题;第一种反爬机制 -- robots.txt
# 解决方法:在settings文件中修改配置 ROBOTSTXT_OBEY = False
配置UA
去所创建项目的settings.py配置
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36'
爬虫文件的返回值(response)
# parse方法的response是请求返回的返回值
div_list = response.xpath('') # div_list为一个列表对象,每一个元素为Selector对象
# 不过用法与lxml中etree.xpath用法一致
提取Selector的文本
1.xpath('//xx/x/text()').extract() # 该方法会将列表中所有的Selector中的文本全部提取
2.xpath('//xx/x/text()').extract_first() # 该方法会将列表中第一个Selector中的文本提取
持久化存储
- 步骤:
# 注意:默认情况下,管道机制并没有开启.需要手动在配置文件中进行开启
# 使用管道进行持久化存储的流程:
# 1.获取解析到的数据值
# 2.将解析的数据值存储到item对象(item类中进行相关属性的声明)
# 3.通过yild关键字将item提交到管道
# 4.管道文件中进行持久化存储代码的编写(process_item)
# 5.在配置文件中开启管道
一.基于终端命令进行存储
# 基于终端指令的持久化存储:可以通过终端指令的形式将parse方法的返回值中存储的数据进行本地磁盘的持久化存储
# return all_data
'''在终端运行文件 :scrapy crawl 爬虫文件名 -o(存储文件命令) xx.txt(不能存储为txt形式,可以先运行此命令,系统会提示可以将数据存储为何种形式)''' 如上图所示
二.基于数据库存储
item.py:
class BossproItem(scrapy.Item):
'''define the fields for your item here like:
name = scrapy.Field()
title = scrapy.Field()
salary = scrapy.Field()
company = scrapy.Field()
'''
爬虫文件:实例化一个BossproItem对象
# item = BossproItem()
# item['xx'] = 所爬取的数据 xx为item中所定义的字段
....
#将item对象提交给管道进行持久化存储
yield item # 包含你想要存储的数据 发送给pipelines.py
pipelines.py:
如下图⬇⬇⬇⬇
重写父类的方法:open_spider(self,spider)与close_spider(self,spider)
# spider为你创建的爬虫文件对象
基于文件存储
基于mysql存储
基于Redis存储
# 一定记得开启管道!!!
scrapy的cookie处理
我们知道,一些网站的进入需要cookie
例如:QQ空间的登录等...如果我们爬虫需要模拟登录后需要拿到详情页面,需要携带cookie, 那么scrapy是如何处理cookie?
在一般情况下,我们会在登录后通过请求头拿到cookie,然后将cookie加入进headers中,然后拿到用户详情页面数据
scrapy不需要,只需要将配置修改 初始是注释(自动处理cookie),如果你发送请求时scrapy会携带cookie,不需要我们主动去获取cookie
是不是很方便啊
scrapy发送post请求
# FormRequest可以发送post请求
# 该方法的formdata接收发送的数据,数据类型为字典
scrapy请求传参
# 当使用scrapy进行数据爬取的时候,如果发现爬取的数据值没有在同一张页面中进行存储.则必须使用请求传参进行处理(持久化)
# 将item实例化的对象作为全局变量会出点小问题 (值有些会被覆盖)
# scrapy.Request方法或scrapy.FormRequest方法中的meta可以传参,meta为一个字典类型
# 接收时可以用response.meta接收然后赋给一个变量
提升爬取的效率
通常,我们使用多线程可以提升效率
scrapy可以通过修改配置提升爬取的效率
修改配置:
# 增加并发:
# 默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
CONCURRENT_REQUESTS = 10
# 降低日志级别:
# 在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:
LOG_LEVEL = ‘INFO’ LOG_LEVEL = 'ERROR'
# 禁止cookie:
# 如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:
COOKIES_ENABLED = False
# 禁止重试:
# 对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:
RETRY_ENABLED = False
# 减少下载超时:
# 如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:
DOWNLOAD_TIMEOUT = 10 超时时间为10s
UA池与代理池
先了解scrapy的框架
https://www.jianshu.com/p/8e78dfa7c368
看代码吧(说不太清,或者看书)
CrawlSpider
'crawlspider是Spider的派生类(一个子类),Spider类的设计原则是只爬取start_url列表中的网页,而CrawlSpider类定义了一些规则(rule)来提供跟进link的方便的机制,从爬取的网页中获取link并继续爬取的工作更适合。'
crawlspider的使用
https://www.jianshu.com/p/a6a08b4f7c04
一.创建项目: scrapy startsproject 项目名
cd 项目名
创建爬虫文件:scrapy genspider -t crawl 文件名 起始url(www.xxx.com)
例 :如下为创建的爬虫文件
# -*- coding: utf-8 -*-
import scrapy
# 导入CrawlSpider相关模块
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
# 表示该爬虫程序是基于CrawlSpider类的
class CrawldemoSpider(CrawlSpider):
name = 'crawlDemo' #爬虫文件名称
#allowed_domains = ['www.qiushibaike.com']
start_urls = ['http://www.qiushibaike.com/']
#连接提取器:会去起始url响应回来的页面中提取指定的url
link = LinkExtractor(allow=r'/8hr/page/\d+')
#rules元组中存放的是不同的规则解析器(封装好了某种解析规则)
rules = (
#规则解析器:可以将连接提取器提取到的所有连接表示的页面进行指定规则(回调函数)的解析
Rule(link, callback='parse_item', follow=True),
)
# 解析方法
def parse_item(self, response):
# print(response.url) 返回的是相似的url
divs = response.xpath('//div[@id="content-left"]/div')
for div in divs:
author = div.xpath('./div[@class="author clearfix"]/a[2]/h2/text()').extract_first()
print(author)
<!-- CrawlSpider类和Spider类的最大不同是CrawlSpider多了一个rules属性,其作用是定义”提取动作“。在rules中可以包含一个或多个Rule对象,在Rule对象中包含了LinkExtractor对象。 -->
分布式爬虫
-- 为了加快数据的爬取效率
步骤一.
1.安装模块:pip3 install redis_scrapy
2.创建项目 scrapy startsproject 项目名
cd 项目名
3.创建爬虫文件:scrapy genspider 文件名 起始url(www.xxx.com)
步骤二.修改爬虫文件
1.导入scrapy_redis模块: from scrapy_redis.spiders import RedisSpider
2.将当前爬虫的父类修改成 RedisSpider
3.将allowed_domains和start_urls注释(分布式,不能每一个爬虫文件都有一个起始url)
4.添加一个新的属性 redis_key = "xxx",该属性表示的是可以被共享的调度器队列的名称
步骤三.修改配置文件(settings.py)
1.保证爬虫文件所提交的请求都会被提交到共享的调度器的队列中
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
2.保证爬虫文件提交的item会被提交到共享的管道中
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 400
}
3.配置最终数据存储的redis数据库
REDIS_HOST = 'redis服务的ip地址'
REDIS_PORT = 6379
REDIS_ENCODING = ‘utf-8’
REDIS_PARAMS = {‘password’:’123456’}
4.redis数据库的配置文件进行配置:关闭保护模式和注释掉bind 127.0.0.1
5.开启redis服务和客户端
6.执行爬虫文件:scrapy runspider xxx.py
7.向调度器队列中仍入一个起始的url:
# 进入redis-cli中:lpush key value
# key为redis_key
# value为起始url
settings中加入如下配置:
# 使用的是可以被共享的调度器
# 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis组件自己的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据
SCHEDULER_PERSIST = True
运行文件:
***切换到spider目录下,运行命令:
scrapy runspider 爬虫文件.py
运行文件后会卡在listen处 ---> 等待一个url
执行步骤三中的第7步,程序将继续向下执行
增量式爬虫
增量式爬虫:每次爬取网站中更新的数据.
定时爬虫:使用脚本在指定时间内进行一次数据(最新更新)的爬取.
爬取数据的流程:
1.指定url
2.根据指定的url发请求,获取页面数据
3.持久化存储
案例:
实现增量式爬虫的方案:
1.在发送请求之前,判断url之前是否爬取过
a.将即将进行爬取的数据对应的url存储到redis的set中.
2.根据爬取到的数据进行重复过滤,然后在进行持久化存储
b.将爬取到的数据给其生成一个唯一的标识(可以将该标识作为mysql的列.可以将该标识存储到redis的set中)
自定义增量式爬虫
将爬取的url或数据进行唯一标识
ex = redis.sadd(key,value)
若ex返回值为1,则该数据将会放入redis数据库中
若返回为0,则说明redis数据库中存在该数据
判断ex的返回值可以进行爬取网页更新的数据
# 看爬虫文件的day07部分