python爬虫学习笔记1

爬虫
概念:模拟浏览器,发送请求,获取相应
作用:数据采集、软件测试、抢票、网站上的投票、网络安全(漏洞扫描)
分类:
爬取网站数量不同:通用爬虫,搜索引擎;聚焦爬虫,专门抓取一个或某一类网站数据
是否以获取数据为目的:功能性爬虫,投票,点赞;数据增量爬虫,比如获取招聘信息;而数据增量爬虫又可以分为两类,url与数据同时变,url不变,数据变

过程:
url_list,发送请求(http协议)获取响应,解析响应,提取url(翻页/详情),提取数据,保存数据
HTTP:超文本传输协议,默认端口号80;
HTTPS:HTTP+SSL(安全套接字层,对请求体或响应体进行加密处理),即带有安全套接字层的超文本传输协议,默认端口号443

常见的请求头与响应头
请求头
host:域名
Connection:长连接
Upgrade-Insecure-Requests:升级为安全的HTTPS请求
User-Agent:用户代理,告诉服务器浏览器和机器的一些信息
Referer:页面跳转处,即当前请求是从哪个页面url跳转过来的,用于检测请求的合法性,防盗链(图片/视频),在本网站可以显示,但是拿着url去其他网站就不能正常显示
Cookie:状态保持,判断是否是某个用户
其中User-Agent、Referer、Cookie用得最多,在服务器被用来进行爬虫识别的频率最高,比较其余的请求头更为重要,但是这里需要注意的是并不意味着其余的不重要,因为有的网站的运维或者开发人员可能剑走偏锋,会使用一些比较不常见的请求头来进行爬虫的甄别

响应头
爬虫只关注一个响应头字段
Set-Cookie:对方服务器设置cookie到用户浏览器的缓存

网站运维和开发程序员可能在状态码中做手脚:具体表现为爬虫程序或得到的状态码为200,但没有数据,其实你已经被识别为爬虫,只是网站运维程序员故意假装没识别出来;又或者返给你503的状态码,让你以为是服务器内部出现了问题
因此所有的状态码都不可信,一切以是否能从抓包得到的响应中获取到数据为准
network中抓包得到的源码才是判断依据,elements中的源码是渲染之后的源码,不能作为判断标准;所有network中的内容渲染汇总才得到的elements

http请求的过程
1.浏览器在拿到域名对应的ip后,先向地址栏中的url发起请求,并获取响应;
2.在返回的响应内容(html)中,会带有css、js、图片等url地址,以及ajax代码,浏览器按照响应内容中的顺序依次发送其他的请求,并获取响应;
3.浏览器每获取一个响应就对展示出的结果进行添加(加载),js、css等内容会修改页面的内容,js也可以重新发送请求,获取响应;
4.从获取第一个响应并在浏览器中展示,直到最终获取全部响应,并在展示的结果中添加内容或修改===这个过程就叫做浏览器的渲染。
注意::::
但是在爬虫中,爬虫只会请求url地址,对应的拿到url地址对应的响应(改响应的内容可以是html,css,js,图片等)
浏览器渲染出来的页面和爬虫请求的页面很多时候并不一样,是因为爬虫不具备渲染的能力(当然后续课程中我们会借助其他工具或包来帮助爬虫对响应内容进行渲染)
简单点说:浏览器发送所有请求,进行渲染;爬虫只发送指定请求,不会渲染。

浏览器最终展示的结果是由多个url地址分别发送的多次请求对应的多次响应共同渲染的结果
所以在爬虫中,需要以发送请求的一个url地址对应的响应为准来进行数据的提取。

浏览器请求的抓包文件可以分为三类:
骨骼文件:html静态文件
肌肉文件:js文件,ajax请求
皮肤文件:css文件,font文件,图片,视频文件等

抓包过程:根据请求的流程分别在骨骼文件、肌肉文件、皮肤文件响应中查找数据

1、response.text是requests模块按照charset模块推测出的编码字符集并进行解码的结果
2、网络传输的字符串都是bytes类型的,所以response.text = response.content.decode('推测出的编码字符集')
3、我们可以在网页源码中搜索charset,尝试参考该编码字符集,注意存在不准确的情况
4、response.text:str类型,requests模块自动根据HTTP头部对响应的编码作出有根据的推测,推测的文本编码;response.content:bytes类型,解码类型需手动指定

response响应对象的其他常用属性或方法
response.url:响应的url,有时候响应的url和请求的url并不一致
response.status_code:响应状态码
response.request.headers:响应对应的请求头
response.headers:响应头
response.request._cookies:响应对应请求的cookie;返回cookieJar类型
response.cookies:响应的cookie(经过了set-cookie动作,返回cookieJar类型)
response.json():自动将json字符串类型的响应内容转为python对象(dict或list)

发送带参数的请求:
1.url中直接带参数:https://www.baidu.com/s?wd=python
2.使用params参数:构建参数字典,发送请求的时候设置参数字典

在headers中携带cookies,方法同User-Agent
还可以使用cookies参数保持会话:构建cookies字典,再请求的时候将cookies字典赋值给cookies参数
注意cookie一般是有过期时间的,一旦过期需要重新获取

理解使用代理的过程
1.代理ip是一个ip,指向的是一个代理服务器
2.代理服务器能够帮我们向目标服务器转发请求
根据代理的匿名程度,分为透明代理、匿名代理和高匿名代理

代理参数的使用
proxies = {'http(s)': 'http://12.24.56.67:4353', }
代理使用成功不会有任何报错,如果使用失败则会报错或者一直等待
requests.get(url, verify=False)# 绕过CA证书

requests发送post请求的方法
resp = requests.post(url, data=data)
data参数接受一个字典,requests模块发送post请求函数的其他参数(除了data参数 )和发送get请求的参数完全一致

post数据来源
1.固定值:抓包比较不变值
2.输入值:抓包比较根据自身变化值
3.预设值:静态文件中的html中获取(多使用正则表达式),再构造到提交data中
4.预设值:发请求,需要对指定地址发送请求获取数据
5.在客户端生成的:分析js,模拟生成数据

利用requests.session进行状态保持
requests模块中的Session类能够自动处理发送请求获取响应过程中产生的cookie,进而达到状态保持的目的。
requests.session的作用以及应用场景
作用:自动处理cookie,即下一次请求会带上前一次的cookie
应用场景:自动处理连续的多次请求过程中产生的cookie
session实例在请求了一个网站后,对方服务器设置在本地的cookie会保存在session中,
下一次再使用session请求对方服务器的时候,会带上前一次的cookie
session对象发送get或post请求的参数,与requests模块发送请求的参数完全一致

document类型就是静态文件:
XHR就是所有的ajax请求文件
可以通过Ctrl加选多种类型的文件
点击一个文件,去response中查找所需要的数据(查找中文的话建议去preview中找)

响应内容的分类
结构化的响应内容
1.json字符串(高频出现):可以使用re、json、jsonpath(重要性远不如re和json)等模块来提取特定数据
2.xml字符串(目前用的比较少):可以用re、lxml等模块来提取特定数据

非结构化的响应内容
html字符串:可以使用re、lxml等模块来提取特定数据

xml和html的区别
html:超文本标记语言;为了更好的显示数据,侧重点是为了显示
xml:可扩展标记语言;为了传输和数据存储,侧重点是在于数据内容本身

re模块最快,lxml模块其次,beautifulsoup模块最慢

jsonpath使用场景:多层嵌套的复杂字典直接提取数据
谷歌插件xPath Helper百度网盘链接和提取码
1、https://pan.baidu.com/s/1UM94dcwgus4SgECuoJ-Jcg; 337b
2、Windows平台需要把下载的文件的后缀名crx改为rar,然后解压到同名文件夹中
3、把解压后的文件夹拖入到已经开启开发者模式的chrome浏览器扩展程序界面

xpath定位节点以及提取属性或文本内容的语法
表达式
nodename:选中该元素
/:从根节点选取、或者是元素间的过渡
//:从匹配选择的当前节点选择文档中的节点,而不考虑他们的位置
.:选取当前节点
..:选取当前节点的父节点
@:选取属性
text():选取文本

注意:/隔开的永远是节点
//link/@href、//a/text()

xpath修饰语法:选取特定节点
1.通过索引修饰节点:div[1]第一个div;div[last()-1]倒数第二个div
div[position()>=10]:区间范围选择
2.通过属性值修饰节点: //div[@id='content']/div/@id,@在最后,代表取值
3.通过子节点的值修饰节点://div[span[2 ]>500]
4.通过包含修饰://div[contains(@id,"qiushi_tag_")]、//span[contains(text(),"下一页")]
5.xpath符合语法|://td/a|//h2/a

html = etree.HTML(text):将html源码创建成element对象,并且能够自动补全html缺失的标签
etree.tostring(html):可以将转换成的element对象,再转回html字符串
爬虫如果使用lxml来提取数据,应该以etree.tostring的返回结果作为提取数据的依据

常见的反爬手段和解决思路
一、服务器反爬的原因
1.爬虫占总PV(指页面的访问次数,每打开或刷新一次页面,就算做一个PV)比例较高,这样浪费钱(尤其是三月份爬虫,硕士写论文抓取数据)
2.公司可免费查询的资源被批量抓走,丧失竞争力,这样少赚钱;
3.状告爬虫成功的机率小:爬虫在国内还是个擦边球,就是有可能可以起诉成功,也可能完全无效。所以还是需要用技术手段来做最后的保障。

二、服务器常反什么样的爬虫
1.十分低级的应届毕业生
2.十分低级的创业公司
3.不小心写错了没人去停止的失控小爬虫
4.成型的商业对手
5.抽风的搜索引擎

三、反爬虫领域常见的一些概念

四、反爬的三个方向
1.基于身份识别进行反爬
2.基于爬虫行为进行反爬
3.基于数据加密进行反爬

五、常见基于身份识别进行反爬
1.通过headers字段反爬
1.1通过headers中User-Agent字段反爬
反爬原理:爬虫默认情况下没有User-Agent,而是使用模块默认设置
解决方法:请求之前添加User-Agent即可,更好的方式是使用User-Agent池来解决(收集一堆User-Agent的方式,或者随机生成User-Agent)
1.2通过Referer字段或者是其他字段来反爬
反爬原理:爬虫默认情况下不会带上referer字段,服务器通过判断请求发起的源头,以此判断请求是否合法
解决方法:添加referer字段
1.3通过cookie来反爬
反爬原因:通过检查cookies来查看发起请求用户是否具备相应权限,以此来进行反爬
解决方法:进行模拟登陆,成功获取cookie之后再进行数据爬取

2、通过请求参数来反爬
请求参数的获取方式有很多,向服务器发送请求,很多时候需要携带请求参数,通常服务器端可以通过检查请求参数是否正确来判断是否为爬虫
2.1通过从html静态文件中获取请求数据(github登录数据)
反爬原因:通过增加获取请求参数的难度进行反爬
解决方法:仔细分析抓包得到的每一个包,搞清楚请求之间的联系
2.2通过增加发送请求获取请求数据
反爬原因:通过增加获取请求参数的难度进行反爬
解决方法:仔细分析抓包得到的每一个包,搞清楚请求之间的联系,搞清楚请求参数的来源
2.3通过js生成请求参数
反爬原理:js生成了请求参数
解决方法:分析js,观察加密的实现过程,通过js2py获取js的执行结果,或者使用selenium来实现
2.4通过验证码来反爬
反爬原理:对方服务器通过弹出验证码强制验证用户浏览行为
解决方法:打码平台或者是机器学习的方法识别验证码,其中打码平台廉价易用,更值得推荐

六、常见基于爬虫行为进行反爬
1.基于请求频率或总请求数量
爬虫的行为与普通用户有着明显的区别,爬虫的请求频率与请求次数要远高于普通用户
1.1通过请求ip/账号单位时间内总请求数量进行反扒
反爬原理:正常浏览器请求网站,速度不会太快,同一个ip/账号大量请求了对方服务器,有更大的可能性被识别为爬虫
解决方法:对应的通过购买高质量的ip的方式能够解决问题,购买多个账号

1.2通过同一ip/账号请求之间的间隔进行反爬
反爬原理:正常人操作浏览器网站,请求之间的时间间隔是随机的,而爬虫前后两个请求之间时间间隔通常比较固定,同时时间间隔较短,因此可以用来做反爬
解决方法:请求之间进行随机等待,模拟真实用户操作,在添加时间间隔后,为了能够高速获取数据,尽量使用代理池,如果是账号,则将账号请求之间设置随机休眠

1.3通过对请求ip/账号每天请求次数设置阈值进行反爬
反爬原理:正常的浏览行为,其一天的请求次数是有限的,通常超过某一个值,服务器就会拒绝响应
解决方法:对应的通过购买高质量的ip/多账号,同时设置请求时间随机休眠

2根据爬取行为进行反爬,通常爬取步骤上做分析
2.1通过js实现跳转来反爬
反爬原理:js实现页面跳转,无法在源码中获取下一页url
解决方法:多次抓包获取跳转url,分析规律

2.2通过蜜罐(陷阱)获取爬虫ip(或者代理ip),进行反爬
反爬原理:在爬虫获取链接进行请求的过程中,爬虫会根据正则,xpath,css等方式进行后续链接的提取,此时服务器端可以设置一个陷阱url,会被提取规则获取,但是正常用户无法获取,这样就能有效的区分爬虫和正常用户
解决方法:完成爬虫的编写之后,使用代理批量爬取测试,仔细分析响应内容结构,找出页面中存在的陷阱

2.3通过加数据进行反爬
反爬原理:向返回的响应中添加假数据污染数据,通常假数据不会被正常用户看到
解决方法:畅起运行,和对数据库中数据与实际页面中数据对应情况,如果存在问题,仔细分析响应内容

2.4阻塞任务队列
反爬原理:通过生成大量垃圾url,从而阻塞任务队列,降低爬虫的实际工作效率
解决方法:观察运行过程中请求响应状态,仔细分析源码获取垃圾url生成规则,对URL进行过滤

2.5阻塞网络IO
反爬原理:发送请求获取响应的过程实际上是下载的过程,在任务队列中混入一个大文件的url,当爬虫在进行该请求时将会占用网络IO,如果是多线程则会占用线程
解决方法:观察爬虫运行状态/多线程对请求线程计时/发送请求线,仔细审查url,过滤掉特殊异常url

七、常见基于数据加密进行反爬
对响应中含有的数据进行特殊化处理
通常的特殊化处理主要指的就是CSS数据偏移/自定义字体/数据加密/特殊编码格式等
1.1通过自定义字体来反爬(猫眼电影PC版)
反爬思路:使用自定义字体文件
解决思路:切换到手机版/解析字体文件进行翻译
1.2通过css来反爬(去哪儿PC版)
反爬思路:源码数据不为真正数据,需要通过css位移才能产生真正数据
解决思路:计算css的偏移
pip install --index https://mirrors.ustc.edu.cn/pypi/web/simple/ selenium

js解析
一、定位js文件
1.根据initiator定位js文件
2.通过searc搜索关键字定位到js文件
3.通过元素绑定的事件监听函数找到js文件
注:三种方法不保证每一种都能找到js文件,三种都使用来进行定位

二、分析js代码,掌握加密步骤
三、模拟加密步骤,使用python方法重现

一、scrapy的概念和流程
Scrapy的是一个python编写的开源网络爬虫框架,它是一个被设计用于爬取网络数据,提取结构性数据的框架
它使用了Twisted异步网络框架,可以加快我们的下载速度

二、scrapy的作用
少量的代码,就能够快速的爬取

三、scrapy的工作流程
回顾一下之前的爬虫流程
url队列,发送请求获取响应,解析响应,提取数据,下一个url(循环操作)

scrapy的三个内置对象
1.request请求对象:由url、method、post_data headers等构成
2.response响应对象:由url、body、status、headers等构成
3.item数据对象:本质是个字典

scrapy中每个模块的作用
1.Scrapy Engine(引擎):总指挥,负责数据和信号在不同模块间的传递,scrapy已经实现
2.Scheduler(调度器):一个队列,存放引擎发过来的request请求,scrapy已经实现
3.Downloader(下载器):下载引擎发过来的request请求,并返回给引擎,scrapy已经实现
4.Spider(爬虫):处理引擎发来的response,提取数据,提取url,并交给引擎,需要手写(起始的url,解析)
5.Item Pipeline(管道):处理引擎传过来的数据,比如存储,需要手写(保存数据)
6.Downloader Middlewares(下载中间件):可以自定义的下载扩展,比如设置代理,一般不用手写
7.Spider MiddlewaresSpider(爬虫中间件):可以自定义requests请求和进行response过滤,一般不用手写(定制化操作)

scrapy安装
pip install --index https://mirrors.ustc.edu.cn/pypi/web/simple/ scrapy

scrapy项目开发流程
1.创建项目
scrapy startproject YourSpider
2.生成一个爬虫
scrapy genspider yourspider
3.提取数据
根据网站结构在spider中实现数据采集相关内容
4.保存数据
使用pipeline进行数据后续处理和保存

创建项目
通过命令将scrapy项目的文件生成出来,后续步骤都是在项目文件中进行相关操作,
下面以抓取传智播客师资库来学习scrapy的入门使用:http://www.itcast.cn/channel/teacher.shtml
创建scrapy项目的命令:scrapy startproject <项目名字>
scrapy.cfg:项目的配置文件
spiders:自己定义的spider的文件夹
settings.py:设置文件,User-Agent,启动管道
pipelines.py:管道,保存数据
middlewares.py:自定义中间件的文件
items.py:自己预计需要爬取的内容

创建爬虫
通过命令创建出爬虫文件,爬虫文件为主要的代码作业文件,通常一个网站的爬取动作都会在爬虫文件中进行编写
命令:在项目路径下执行:scrapy genspider <爬虫名字><允许爬取的域名>
爬虫名字:作为爬虫运行时的参数
允许爬取的域名:为对于爬虫设置的爬取范围,设置之后用于过滤要爬取的url,如果爬取的url与允许的域不同则被过滤掉

运行scrapy
命令:在项目目录下执行scrapy crawl <爬虫的名字>

爬虫文件的介绍
三个参数
name:爬虫的名字
allowed_domains:允许爬取的域名
start_urls:设置起始的url,会被爬虫框架自动发起请求,并把响应传递给parse方法

windows查看当前目录结构

tree /f

E:/Data is not a Spyder project
解决办法:新建一个空的Spyder项目文件,把里面的.spyproject文件夹复制到Data文件夹

完成爬虫
1.修改其实的url
2.检查修改允许的域名
3.在parse方法中实现爬取逻辑(如果逻辑复杂,可再编写其他解析方法)

带日志启动爬虫命令# scrapy crawl itcast

不带日志启动爬虫命令# scrapy crawl itcast --nolog

注意
1、scrapy.Spider爬虫类中必须有名为parse的解析函数
2、如果网站结构层次比较复杂,可以自定义其他解析函数
3、在解析函数中提取的url地质如果要发送请求,则必须属于allowed_domain范围内,但是start_urls中的url地址不受这个限制,我们会在后续的课程学习中学习如何在解析函数中构造发送请求
4、启动爬虫的时候注意启动的位置,是在项目路径下启动
5、parse()函数中使用yield返回数据。注意:解析函数中的yield能够传递的对象只能是BaseItem,Request,dict和None

定位元素以及提取数据、属性值的方法
解析并获取scrapy爬虫中的数据,利用xpath规则字符串进行定位和爬取
1.response.xpath方法返回的是一个类似于list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
2.额外方法extract():返回一个包含有字符串的列表
3.额外方法extract_first():返回列表中的第一个字符串,列表为空返回None

response响应对象的常用属性
response.url:当前响应的url地址
request.url:当前响应对应的请求的url地址
headers:响应头
request.headers:当前响应的请求头
body:响应体,也就是html代码,byte类型
status:响应状态码

DOS:向上键可以执行上一次相同的命令

保存数据
利用管道pipeline来处理保存数据
1.在pipelines.py文件中定义对数据的操作
定义一个管道类
重写管道类的process_item方法
process_item方法处理完之后必须返回给引擎
2.在settings.py配置启用管道
ITEM_PIPELINES = {
'myspider.pipelines.ItcastPipeline': 400#应用哪个目录哪个文件定义的哪个管道类,300代表执行顺序,谁小谁优先执行
}

1.数据建模
通常在做项目的过程中,在items.py中进行数据建模
1.1为什么建模
1.定义item即提前规划好哪些字段需要抓取,防止手误,因为定义好之后,在运行过程中,系统会自动检查
2.配合注释一起可以清晰的知道要抓取哪些字段,没有定义的字段不能抓取,在目标字段少的时候可以使用字典替代
3.使用scrapy的一些特定组件需要Item做支持,如scrapy的ImagesPipeline管道类,百度搜索了解更多
1.2如何建模
在items.py文件中定义要提取的字段:
class MyspiderItem(scrapy.Item):
name = scrapy.Field()#讲师的名字
title = scrapy.Field()#讲师的职称
desc = scrapy.Field()#讲师的介绍

开发流程总结
1.创建项目
scrapy startproject 项目名
2.明确目标
在items.py文件中进行建模
3.创建爬虫
3.1scrapy genspider 爬虫名 允许的域
3.2完成爬虫
修改start_urls
检查修改allowed_domains
编写解析方法
4.保存数据
在pipelines.py文件中定义对数据处理的管道
在settings.py文件中注册启用管道

构造Request对象,并发送请求
3.1实现方法
确定url地址
构造请求,scrapy.Request(url,callback)
callback:指定解析函数名称,表示该请求返回的响应使用哪一个函数进行解析
把请求交给引擎,yield scrapy.Request(url,callback)

cd ..返回上一级目录
https://hr.163.com/position/list.do

scrapy模拟登录
学习目标
1.应用请求对象cookie参数的使用
2.了解start_requests函数的作用
3.应用构造并发送post请求

1.回顾之前的模拟登录方法
1.1requests模块的模拟登录方法
1.直接携带cookies请求页面
2.找url地址,发送post请求存储cookie
1.2selenium是如何模拟登录的?
找到对应的input标签,输入文本点击登录
1.3scrapy的模拟登陆
1.直接携带cookies
2.找url地址,发送post请求存储cookie

scrapy携带cookies直接获取需要登录的页面
应用场景
1.cookie过期时间很长,常见于一些不规范的网站(地方性政府)
2.能在cookie过期之前把所有的数据拿到
3.配合其他程序使用,比如其使用selenium把登录之后的cookie获取到保存到本低,scrapy发送请求之前先读取本地cookie
2.1实现:重构scrapy的start_requests方法
scrapy中start_urls是通过start_requests来进行处理的

重写start_requests(self)方法
def start_requests(self):
url = self.start_urls[0]
# 拿到登录后的cookie,构造cookie字典
temp = '_ga=GA1.2.1210121656.1553845768; _octo=GH1.1.612568455.1553845769; _device_id=4fd174d4b3cb4f94f72bff21dbca9cf9; tz=Asia%2FShanghai; has_recent_activity=1; user_session=y3ej_ACURi0zLo7Xd9LEdrCtIVfgHlQkYd8Yz3J_MN5Fx5Mc; __Host-user_session_same_site=y3ej_ACURi0zLo7Xd9LEdrCtIVfgHlQkYd8Yz3J_MN5Fx5Mc; tz=Asia%2FShanghai; color_mode=%7B%22color_mode%22%3A%22light%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; logged_in=yes; dotcom_user=feijiang-cloud; _gh_sess=eHRZVh%2FdPfe2lESPdcjD2YS8ngYnxhkQxHpUcJS%2B1yqRcbnyBdU%2BdmcvQFTL7RP6gc%2BXkhpehaWXOzICqmlbr6wENmmRiQO%2FKQh%2B%2FqSvUzhIG7EoHsmigxCpQmkOs52mVDzOjAfkn%2FC8%2Bp5Nn3BttUyHKHT%2FJGnkHP4BFhvfk%2BgobQqjGC9g2%2BdMFqzw9vBm5h2JRhbzI3HJJXvy8fspXLV5nUas2hRXHn%2B62ncVBOFH8ALMx%2FAcwaOPpUw8eNCnOaWVIXS%2BMH4Vcnp%2FBPRhGS2rUYPc8vT3fiRHMirSKlXCiuSumfVitS9QBP5ABN5SpINl17E4p6CBuJpkmqpVepDGlsUS31qoFh%2BQA6FUNkV7uHXUNa9i8o4BM6aqelEPuY7nk3usOKj6o%2FwrlyNWv9WAdY02bHI%2FE0rLlziPC3RqN9jIiyQzl7dpLhxbfZP2o0uKxBTvm5QznUG7WJkBZ8wihieCu25M0ZXc%2F3emboAbhoymah7ZIuj2AdpYrhEjSKwI1RuRRRkSGazud%2FLBlaQuAkPGVSY3%2B1C9JtOGWejRFWQrboxbxORx52I3gIM6vO0DvZ3NyZz71rOtWM%2F%2BYiIhagoBt1hSjE0q%2BElFLfE6gA3q8%2BlnttGSU3v0vB52kCvUqekdtAiGe8fSjx%2B8XItyy198X3jdwAqzfLo1OX0%2F%2BO3%2Fiv6JJlzFJBrYDO3Af5GWx7ony7Qh%2FTfu5NvJdAkDK1phfu8yk52nQnvFN2ut70IBOofR0TXgzbJxiSeA2JaaHGkJ8%2BTxewbRkhBTWV5gfF356g0y1Ktzzi4jdMFhAT4ylbZsmHXERx0hKH4MICV4sxdRWgeMlYM1n3ww4lOyi4qBZNwvJ8L8zaiBbT5p8j4BkGmF3pD5nl%2FxB3YN%2Bi6KmZwlZg%2F9BUe%2Bp7nz9Hlxfn76mR32x%2BkPg4UTx%2BqHcvLyb1c4OBrEUo4BGo0l3swkPatKEEhVJQ8xRbahfI%2Bna0kL9mvcBdihezVWY5ptyF0nkLipp3q5A%2BGvF203BeW5maEXkF4ru0ZDI4ObNpccbHvSQJRpJeGr6nBJAkFB6HmARdZzsasLS52M7PJNmP%2FwOkP9MUh5kxk0NJAXzJEIkvLHd2vROd8TUSugrqi0HgFwgXDGmtY7PhtgreyueDAfoafXjjgXUmVfD9fj9HBaKWwGW%2FOxJiJEsGd573v0apsApp8Ca75CuJMhY8tVVZUFQZ7kOa6fgisMr%2F2AyJIUHCksgzDtw%2BJEsuviZ3zQTclB29g0mf%2BPXnwMQEL%2FNZ4%2BdW1lK%2B60Gq8QrZt%2Bsxh6iQcCQqQoNn%2FxhJ87BoAZZovNKRIrRT714sWXB4InitCIGGY17pNoWJHrt5jM78lkcpFc7WaZFeVqAIZ%2B%2FWNeTr%2BVmYQ67JE%2FOfbK6TPg--copajVr1PiKsDom0--tzPuxaystfXmhNiJvEXNsA%3D%3D'
cookies = {data.split('=')[0]: data.split('=')[1] for data in temp.split('; ')}

    yield scrapy.Request(url=url, callback=self.parse, cookies=cookies)

3.scrapy.Request发送请求
我们知道可以通过scrapy.Request()指定method、body参数来发送post请求,但是通常使用scrapy.FormRequest()来发送post请求
发送post请求
注意scrapy.FormRequest()能够发送表单和ajax请求
思路分析
找到post的url地址:点击登录按钮进行抓包,然后定位url地址为https://github.com/session
找到请求体的规律,分析post请求的请求体,其中包含的参数均在前一次的响应中
是否登录成功,通过请求个人主页,观察是否含用户名

设置随机请求头与代理IP

import random

从settings配置文件中导入随机请求头列表,代理IP

from wangyi.settings import USER_AGENTS, PROXIES
import base64

随机请求头中间件

class RandUserAgentMiddleware(object):
# 在这里添加请求头列表
USER_AGENTS = [
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20130331 Firefox/21.0',
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36 Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10',
'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.15 (KHTML, like Gecko) Chrome/24.0.1295.0 Safari/537.15',
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.2; rv:22.0) Gecko/20130405 Firefox/23.0',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36',
'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/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.2 Safari/537.36',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0',
]

def process_request(self, request, spider):
    request.headers['User-Agent'] = random.choice(USER_AGENTS)
    # 把请求交给下载器,所以不需要任何返回

随机代理中间件

class RandProxyMiddleware(object):
# 在这里添加请求头列表

def process_request(self, request, spider):
    PROXIES = [
        {'ip_port': '123.207.53.84:16816', 'user_passwd': 'morganna_mode_g:ggc22qxq'},#有钱人的代理ip
        {'ip_port': '122.234.206.43:9000'},#穷人ip
    ]
    
    proxy = random.choice(PROXIES)
    
    # 有没有账号密码#基本认证和摘要认证
    # 如果是白名单,则不需要认证
    if 'user_passwd' in proxy:#有账号密码,加密认证
        # 对帐号密码进行编码
        base64_user_passwd = base64.b64encode(proxy['user_passwd'])
        # 设置认证
        # request.headers['Proxy-Authorization'] = 'Basic '+base64_user_passwd.decode()
        request.headers['Proxy-Authorization'] = f'{"Basic"} {base64_user_passwd.decode()}'
        # 设置代理
        request.meta['proxy'] = proxy['ip_port']
    else:
        # 设置代理
        request.meta['proxy'] = proxy['ip_port']
        
    # 把请求交给下载器,所以不需要任何返回

selenium动态加载中间件

from selenium import webdriver
import time
from scrapy.http import HtmlResponse

class SeleniumMiddleware(object):

def process_request(self, request, spider):
    # 对含有特殊字符串的需要渲染的url进行渲染
    url = request.url
    
    if 'unique_str' in url:
        driver = webdriver.Chrome()# 这里还可以用无头模式
        driver.get(url)
        
        time.sleep(3)#模拟加载
        html = driver.page_source#渲染之后的源码
        driver.close()

        # 创建响应对象
        response = HtmlResponse(url=url, body=html, encoding='utf8', request=request)
        return response

提升爬虫性能思路
1、gevent协程、线程池、线程池+异步;
2、aiohttp(异步请求)替代requests库(阻塞式请求);
3、JIT(即时编译技术):用到比较耗时的代码块上;
4、解释器直接解释耗时的代码段,如Windows平台使用cpython;
5、写原生的C代码,把几个关键的操作抽离出来,用C来重构,然后直接调用这段C代码(python有直接运行C代码的库)
6、升级硬件配置。

1.3通过js动态生成数据进行反爬
反爬原理:通过js动态生成
解决思路:解析关键js,获得数据生成流程,模拟生成数据

1.4通过数据图片化反爬
58同城短租
解决思路:通过使用图片解析引擎从图片中解析数据

1.5通过编码格式反爬
反爬原理:不使用默认编码格式,在获取响应之后通常爬虫使用utf-8格式进行解码,此时解码结果将会是乱码或者报错
解决思路:根据源码进行多格式解码,获得真正的解码格式

posted on 2021-03-10 15:31  行之间  阅读(923)  评论(0编辑  收藏  举报