Python爬虫实战——反爬机制的解决策略【阿里】
这一次呢,让我们来试一下“CSDN热门文章的抓取”。
话不多说,让我们直接进入CSND官网。
(其实是因为我被阿里的反爬磨到没脾气,不想说话……)
一、URL分析
输入“Python”并点击搜索:
便得到了所有关于“Python”的热门博客,包括 [ 标题,网址、阅读数 ] 等等,我们的任务,就是爬取这些博客。
分析一下上图中曲线处的URL,不难发现:p为页数,q为关键字。
二、XPath路径
打开开发者模式,匹配我们所需信息的标签:
- 通过
//dd[@class='author-time']/span[@class='link']/a/@href
匹配各个博客的URL地址;
- 通过
//h1[@class='title-article']/text()
匹配各个博客的标题。
注意:
对于XPath路径有疑问的话,可复习《XPath语法的学习与lxml模块的使用》。
三、代码实现
1.定制输入框:
keyword = input("请输入关键词:")
pn_start = int(input("起始页:"))
pn_end = int(input("终止页:"))
2.确定URL:
# 注意要+1
for pn in range(pn_start, pn_end+1):
url = "https://so.csdn.net/so/search/s.do?p=%s&q=%s&t=blog&viparticle=&domain=&o=&s=&u=&l=&f=&rbg=0" % (pn, keyword)
3.构建request对象:
# 返回request对象
def getRequest(url):
return ur.Request(
url=url,
headers={
'User-Agent': user_agent.get_user_agent_pc(),
}
)
for pn in range(pn_start, pn_end+1):
url = "https://so.csdn.net/so/search/s.do?p=%s&q=%s&t=blog&viparticle=&domain=&o=&s=&u=&l=&f=&rbg=0" % (pn, keyword)
# 构建request对象
request = getRequest(url)
4.爬取博客网站:
# 打开request对象
response = ur.urlopen(request).read()
# response为字节,可直接进行le.HTML将其解析成xml类型
href_s = le.HTML(response).xpath("//dd[@class='author-time']/span[@class='link']/a/@href")
print(href_s)
输出如下:
5.遍历href_s列表,输出网址和标题:
for href in href_s:
print(href)
response_blog = ur.urlopen(getRequest(href)).read()
title = le.HTML(response_blog).xpath("//h1[@class='title-article']/text()")[0]
print(title)
输出如下:
结果倒是出来了,但 list index out of range
是什么鬼???
6.打印open结果进行检查:
for href in href_s:
try:
print(href)
response_blog = ur.urlopen(getRequest(href)).read()
print(response_blog)
输出如下:
有爬到东西,但似乎不是我们想要的网页内容???看着这乱七八糟的 \x1f\x8b\x08\x00
,我一下子想到了 “ 编码 ” 的问题。
7.九九八十一难:
encode
和decode
;UTF-8
和GBK
;bytes
和str
;urlencode
和unquote
;dumps
和loads
;request
和requests
;- 甚至是
accept-encoding: gzip, deflate
; - ······
- 等等等等;
结果!竟然!都不是!!!啊啊啊啊~ ~ ~ ~
罢了罢了,bug还是要解决的_(:3」∠❀)_
8.灵机一动!难道是 cookie
???
# 返回request对象
def getRequest(url):
return ur.Request(
url=url,
headers={
'User-Agent': user_agent.get_user_agent_pc(),
'Cookie': 'acw_tc=2760825115771713670314014ebaddd9cff4024b9ed3255873ddb28d85e269; acw_sc__v2=5e01b9a7ea60f5bf87d21658f23db9678e320a82; uuid_tt_dd=10_19029403540-1577171367226-613100; dc_session_id=10_1577171367226.599226; dc_tos=q3097q; Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac=1577171368; Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac=1577171368; Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac=6525*1*10_19029403540-1577171367226-613100; c-login-auto=1; firstDie=1; announcement=%257B%2522isLogin%2522%253Afalse%252C%2522announcementUrl%2522%253A%2522https%253A%252F%252Fblog.csdn.net%252Fblogdevteam%252Farticle%252Fdetails%252F103603408%2522%252C%2522announcementCount%2522%253A0%252C%2522announcementExpire%2522%253A3600000%257D',
}
)
输出如下:
成功!!
才明白过来,原来我一直走错了方向啊,竟然是阿里反爬机制搞的鬼。I hate you。╭(╯^╰)╮
9.将网页写入本地文件:
with open('blog/%s.html' % title, 'wb') as f:
f.write(response_blog)
10.加入异常处理代码try-except:
try:
······
······
except Exception as e:
print(e)
讲到这里就结束了,大家有心思的话可以自己再把本文的代码进行完善:比如将异常写入到TXT中,方便后续进行异常分析;比如对爬取结果进行筛选,提高数据的针对性;等等。
全文完整代码:
import urllib.request as ur
import user_agent
import lxml.etree as le
keyword = input("请输入关键词:")
pn_start = int(input("起始页:"))
pn_end = int(input("终止页:"))
# 返回request对象
def getRequest(url):
return ur.Request(
url=url,
headers={
'User-Agent': user_agent.get_user_agent_pc(),
'Cookie': 'uuid_tt_dd=10_7175678810-1573897791171-515870; dc_session_id=10_1573897791171.631189; __gads=Test; UserName=WoLykos; UserInfo=b90874fc47d447b8a78866db1bde5770; UserToken=b90874fc47d447b8a78866db1bde5770; UserNick=WoLykos; AU=A57; UN=WoLykos; BT=1575250270592; p_uid=U000000; Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac=6525*1*10_7175678810-1573897791171-515870!5744*1*WoLykos; Hm_lvt_e5ef47b9f471504959267fd614d579cd=1575356971; Hm_ct_e5ef47b9f471504959267fd614d579cd=5744*1*WoLykos!6525*1*10_7175678810-1573897791171-515870; __yadk_uid=qo27C9PZzNLSwM0hXjha0zVMAtGzJ4sX; Hm_lvt_70e69f006e81d6a5cf9fa5725096dd7a=1575425024; Hm_ct_70e69f006e81d6a5cf9fa5725096dd7a=5744*1*WoLykos!6525*1*10_7175678810-1573897791171-515870; acw_tc=2760824315766522959534770e8d26ee9946cc510917f981c1d79aec141232; UM_distinctid=16f1e154f3e6fc-06a15022d8e2cb-7711a3e-e1000-16f1e154f3f80c; searchHistoryArray=%255B%2522python%2522%252C%2522Python%2522%255D; firstDie=1; Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac=1577156990,1577157028,1577167164,1577184133; announcement=%257B%2522isLogin%2522%253Atrue%252C%2522announcementUrl%2522%253A%2522https%253A%252F%252Fblog.csdn.net%252Fblogdevteam%252Farticle%252Fdetails%252F103603408%2522%252C%2522announcementCount%2522%253A0%252C%2522announcementExpire%2522%253A3600000%257D; TY_SESSION_ID=6121abc2-f0d2-404d-973b-ebf71a77c098; acw_sc__v2=5e01ee7889eda6ecf4690eab3dfd334e8301d2f6; acw_sc__v3=5e01ee7ca3cb12d33dcb15a19cdc2fe3d7735b49; dc_tos=q30jqt; Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac=1577185014',
}
)
# 注意要+1
for pn in range(pn_start, pn_end+1):
url = "https://so.csdn.net/so/search/s.do?p=%s&q=%s&t=blog&viparticle=&domain=&o=&s=&u=&l=&f=&rbg=0" % (pn, keyword)
# 构建request对象
request = getRequest(url)
try:
# 打开request对象
response = ur.urlopen(request).read()
# response为字节,可直接进行le.HTML将其解析成xml类型
href_s = le.HTML(response).xpath("//dd[@class='author-time']/span[@class='link']/a/@href")
# print(href_s)
for href in href_s:
try:
print(href)
response_blog = ur.urlopen(getRequest(href)).read()
# print(response_blog)
title = le.HTML(response_blog).xpath("//h1[@class='title-article']/text()")[0]
print(title)
with open('blog/%s.html' % title, 'wb') as f:
f.write(response_blog)
except Exception as e:
print(e)
except:
pass
全文完整代码(代理IP):
import urllib.request as ur
import lxml.etree as le
import user_agent
keyword = input('请输入关键词:')
pn_start = int(input('起始页:'))
pn_end = int(input('终止页:'))
def getRequest(url):
return ur.Request(
url=url,
headers={
'User-Agent':user_agent.get_user_agent_pc(),
}
)
def getProxyOpener():
proxy_address = ur.urlopen('http://api.ip.data5u.com/dynamic/get.html?order=d314e5e5e19b0dfd19762f98308114ba&sep=4').read().decode('utf-8').strip()
proxy_handler = ur.ProxyHandler(
{
'http':proxy_address
}
)
return ur.build_opener(proxy_handler)
for pn in range(pn_start, pn_end+1):
request = getRequest(
'https://so.csdn.net/so/search/s.do?p=%s&q=%s&t=blog&domain=&o=&s=&u=&l=&f=&rbg=0' % (pn,keyword)
)
try:
response = getProxyOpener().open(request).read()
href_s = le.HTML(response).xpath('//span[@class="down fr"]/../span[@class="link"]/a/@href')
for href in href_s:
try:
response_blog = getProxyOpener().open(
getRequest(href)
).read()
title = le.HTML(response_blog).xpath('//h1[@class="title-article"]/text()')[0]
print(title)
with open('blog/%s.html' % title,'wb') as f:
f.write(response_blog)
except Exception as e:
print(e)
except:pass
为我心爱的女孩~~
Python爬虫实战——反爬机制的解决策略【阿里】的更多相关文章
- Python爬虫实战——反爬策略之模拟登录【CSDN】
在<Python爬虫实战-- Request对象之header伪装策略>中,我们就已经讲到:=="在header当中,我们经常会添加两个参数--cookie 和 User-Age ...
- Python爬虫实战——反爬策略之代理IP【无忧代理】
一般情况下,我并不建议使用自己的IP来爬取网站,而是会使用代理IP. 原因很简单:爬虫一般都有很高的访问频率,当服务器监测到某个IP以过高的访问频率在进行访问,它便会认为这个IP是一只"爬虫 ...
- Python爬虫实战之爬取百度贴吧帖子
大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子.与上一篇不同的是,这次我们需要用到文件的相关操作. 本篇目标 对百度贴吧的任意帖子进行抓取 指定是否只抓取楼主发帖 ...
- 抖音爬虫教程,python爬虫采集反爬策略
一.爬虫与反爬简介 爬虫就是我们利用某种程序代替人工批量读取.获取网站上的资料信息.而反爬则是跟爬虫的对立面,是竭尽全力阻止非人为的采集网站信息,二者相生相克,水火不容,到目前为止大部分的网站都还是可 ...
- python爬虫--cookie反爬处理
Cookies的处理 作用 保存客户端的相关状态 在爬虫中如果遇到了cookie的反爬如何处理? 手动处理 在抓包工具中捕获cookie,将其封装在headers中 应用场景:cookie没有有效时长 ...
- 原创:Python爬虫实战之爬取美女照片
这个素材是出自小甲鱼的python教程,但源码全部是我原创的,所以,猥琐的不是我 注:没有用header(总会报错),暂时不会正则表达式(马上要学了),以下代码可能些许混乱,不过效果还是可以的. 爬虫 ...
- Python爬虫-字体反爬-猫眼国内票房榜
偶然间知道到了字体反爬这个东西, 所以决定了解一下. 目标: https://maoyan.com/board/1 问题: 类似下图中的票房数字无法获取, 直接复制粘贴的话会显示 □ 等无法识别的字 ...
- Python爬虫实战之爬取糗事百科段子
首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...
- Python爬虫实战之爬取糗事百科段子【华为云技术分享】
首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...
随机推荐
- Nginx的应用之动静分离
Nginx 的动静分离 我们通过中间件将动态请求和静态请求进行分离,减少了不必要的请求消耗和延时. 动静分离后,即使动态服务不可用,但静态资源不会受到影响. 应用实例 1.准备环境 系统 角色 主机名 ...
- 数据索引文件idx
数据索引文件idx 数据索引文件idx 数据索引文件idx
- mongoose 与 mylab 的使用 (1)
1.引入mongoose 模块 const mongoose = require('mongoose'); 2.连接数据库 //连接数据库 mongoose.connect( db, {useNew ...
- html5中的选择器
1.html5中的属性选择器 <body> <style type=text/css> <!--1>完全匹配选择器--> [id=test]{ color:r ...
- Hands Off for Mac如何卸载?完全卸载Hands Off的方法
Hands Off for Mac如何卸载?hands off是一款超好用的防火墙软件,在Mac系统上强大且易用,能够控制所有应用的网络连接和文件系统访问,保护我们的隐私数据和系统安全性,如果不需要了 ...
- iSkysoft iMedia Converter Deluxe Mac如何制作视频?视频格式转换工具制作动图的方法
使用iSkysoft iMedia Converter Deluxe Mac如何制作视频?使用视频格式转换工具,你可以轻松进行动图或视频的制作,也可以把你喜欢的视频的某一段提取出来,制作成你自己风格的 ...
- Quartz.Net 任务调度之特性(3)
再实现类中使用,就是继承IJob的类 [PersistJobDataAfterExecution] //执行后的保留作业数据,链式传参(上一次的任务数据) [DisallowConcurrentExe ...
- 切换路由时取消全部或者部分axios请求,并将一些从不需要取消的加入白名单
1. axios拦截器进行配置,除了白名单中的接口,统统保存到全局变量canCancelAxios中 window.canCancelAxios = []; // http request 拦截器 a ...
- sql server 基础语法4 实践练习+子查询
drop table class create table class ( classId ) primary key not null, cName ) ) insert into class ', ...
- [CSP-S模拟测试]:赤(red)(WQS二分+DP)
题目传送门(内部题38) 输入格式 每个输入文件包含多组测试数据.选手应当处理到文件结束($EOF$) 每一组数据包括$3$行. 第$1$行包含三个正整数$n,a,b$,表示有$n$只猫,$gyz$有 ...