首页 文章 精选 留言 我的

精选列表

搜索[爬虫框架],共10000篇文章
优秀的个人博客,低调大师

Python网络爬虫之HTTP的异常处理机制

一、URLError(URL错误异常) 通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生。这种情况下,异常同样会带有"reason"属性,它是一个tuple(可以理解为不可变的数组),包含了一个错误号和一个错误信息。看下面的示例 URLError 从程序中可以看到输出为:[Errno 11004] getaddrinfo failed,也就是说,错误号是11004,内容是getaddrinfo failed 二、HTTPError(HTTPError状态错误) 服务器上每一个HTTP 应答对象response包含一个数字"状态码"。有时状态码指出服务器无法完成请求。默认的处理器会为你处理一部分这种应答。例如:假如response是一个"重定向",需要客户端从别的地址获取文档,urllib2将为你处理。其他不能处理的,urlopen会产生一个HTTPError。典型的错误包含"404"(页面无法找到),"403"(请求禁止),和"401"(带验证请求)。HTTP状态码表示HTTP协议所返回的响应的状态。比如客户端向服务器发送请求,如果成功地获得请求的资源,则返回的状态码为200,表示响应成功。如果请求的资源不存在, 则通常返回404错误。 HTTP状态码通常分为5种类型,分别以1~5五个数字开头,由3位整数组成,如:200代表请求成功、304代表请求的资源未更新、400 代表非法请求,详情见HTTP状态码解析 HTTPError实例产生后会有一个整型'code'属性,是服务器发送的相关错误号。 Error Codes错误码:因为默认的处理器处理了重定向(300以外号码),并且100-299范围的号码指示成功,所以你只能看到400-599的错误号码。BaseHTTPServer.BaseHTTPRequestHandler.response是一个很有用的应答号码字典,显示了HTTP协议使用的所有的应答号。当一个错误号产生后,服务器返回一个HTTP错误号,和一个错误页面。你可以使用HTTPError实例作为页面返回的应答对象response。这表示和错误属性一样,它同样包含了read,geturl,和info方法。 HTTPError 从程序中可以看到输出了404的错误码,也就说没有找到这个页面。 三、HTTP异常处理方式 HTTP异常处理方式 从示例中可以看到,两种方式都能输出异常:其中第二种中HTTPError必须写在URLError异常前,因HTTPError是URLError的子类,如果URLError在前面它会捕捉到所有的URLError(包括HTTPError )。

优秀的个人博客,低调大师

Python爬虫入门教程 49-100 Appium安装+操作51JOB_APP(模拟手机操作之一)手机APP爬虫

爬前准备工作 在开始安装Appium之前,你要先知道Appium是做什么的?Appium 是一个自动化测试开源工具,看到没,做测试用的,它有点类似Selenium,可以自动操作APP实现一系列的操作。 标记重点,可以使用python对Appium编写脚本,实现对App的抓取。 今天就给你写一个100%叫你可以运行起来的入门实例。 下载地址 用稳定的最新版本即可。https://github.com/appium/appium-desktop/releases/tag/v1.10.0 下载之后,双击exe安装即可 出现如下界面,表示安装成功,先不要进行其他的操作,点击下面的 Edit Configurations 注意,在弹出的窗口中,需要配置的ANDROID_HOME和JAVA_HOME 这两个路径都需要安装Android Studio才可以配置

优秀的个人博客,低调大师

Python爬虫入门教程 59-100 python爬虫高级技术之验证码篇5-极验证识别技术之二

@[toc] 图片比对 昨天的博客已经将图片存储到了本地,今天要做的第一件事情,就是需要在两张图片中进行比对,将图片缺口定位出来 缺口图片 完整图片 计算缺口坐标 对比两张图片的所有RBG像素点,得到不一样像素点的x值,即要移动的距离 def get_distance(self,cut_image,full_image): # print(cut_image.size) threshold = 50 for i in range(0,cut_image.size[0]): for j in range(0,cut_image.size[1]): pixel1 = cut_image.getpixel((i, j))

优秀的个人博客,低调大师

Python爬虫入门教程 57-100 python爬虫高级技术之验证码篇3-滑动验证码识别技术

滑动验证码介绍 本篇博客涉及到的验证码为滑动验证码,不同于极验证,本验证码难度略低,需要的将滑块拖动到矩形区域右侧即可完成。 这类验证码不常见了,官方介绍地址为:https://promotion.aliyun.com/ntms/act/captchaIntroAndDemo.html使用起来肯定是非常安全的了,不是很好通过机器检测 如何判断验证码类型 这个验证码的标识一般比较明显,在页面源码中一般存在一个 nc.js 基本可以判定是阿里云的验证码了 <script type="text/javascript" src="//g.alicdn.com/sd/ncpc/nc.js?t=1552906749855"></script> 识别套路 截止到2019年3月18日,本验证码加入了大量的selenium关键字验证,

优秀的个人博客,低调大师

异步爬虫里 aiohttp 超时设多少不会误杀正常请求

超时设 3 秒,跑半小时成功率从 98% 掉到 85%。目标站点 RTT 正常,代理 IP 存活,但大量请求抛 ServerTimeoutError。问题出在超时阈值与实际网络时序不匹配,把正常的处理延迟当成了网络故障。aiohttp 超时的实现机制aiohttp 的 ClientTimeout 底层依赖 asyncio 的定时器协程。每一层超时对应一个独立的 asyncio.wait_for 或 loop.call_later 调度,触发时取消对应的协程并抛出 asyncio.TimeoutError,aiohttp 再包装成 aiohttp.ServerTimeoutError。

优秀的个人博客,低调大师

爬虫遇到JS逆向AES加密反爬,哭了

今天准备爬取网页时,遇到『JS逆向AES加密』反爬。比如这样的: 在发送请求获取数据时,需要用到参数params和encSecKey,但是这两个参数经过JS逆向AES加密而来。 既然遇到了这个情况,那么辰哥就教大家如何去解决这类反爬(JS逆向AES加密) 01 网页分析 在开始分析JS逆向AES加密之前,先简单介绍一下要爬取的内容:下载某抑云音乐。其中获取歌曲的真实播放地址m4a的过程涉及到JS逆向AES加密。 点击播放,在浏览器中查看抓取到的数据包,如下图所示: 查看响应数据: 可以看到在url字段中存储着真实播放地址,放到浏览器中打开: 可以看到正常播放,说明歌曲的真实播放地址获取正确。 唯一变的就是data,data里面包含两个参数(params和encSecKey),根据辰哥的经验,这八九不离十是经过JS加密而来,并且肯定跟歌曲的地址有关(浏览器页面地址,非真实播放地址) 02 JS逆向过程 既然知道这两个参数是js逆向加密而来,那直接搜索这两个参数存在于哪个js文件中。 搜索到了5个js,那么就查看这两个参数都同时存在于哪个js中,刚好在第一个js中就看到了。 可以看到params对应的是encText,encSecKey对应的是encSecKey。encText和encSecKey来自于bUE3x,而bUE3x来自于window.asrsea。 varbUE3x=window.asrsea(JSON.stringify(i3x),bsf6Z(["流泪","强"]),bsf6Z(WS0x.md),bsf6Z(["爱心","女孩","惊恐",并以某抑云"大笑"])); 继续搜索window.asrsea 可以看到window.asrsea来源于d,d是一个函数,该函数中返回的h赋值给window.asrsea。这里我们给函数d打断点。 点击刷新网页,重新播放 可以看到函数d需要传入四个参数,通过分析多首歌曲,分析参数e、f、g没变化,唯一变是参数d中的id。 这个id刚好是歌曲的id https://music.163.com/#/song?id=447926067 函数d接收到四个参数后,创建一个字典h(用于存放变量),接着调用函数a,我们继续给函数a打断点。 刷新网页 函数a的作用就是生成一个16为的随机数,下面是函数a运行后最终的参数值,其中c是返回值,因此我们可以认为c是一个固定的值(反正也是随机生成的) a: 16 b: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" c: "z2Ggtvz5ZIsiKO5F" 函数a解析完了,继续分析函数d。 function d(d, e, f, g) { var h = {} , i = a(16); return h.encText = b(d, g), h.encText = b(h.encText, i), h.encSecKey = c(i, e, f), h } 接着经过两次AES加密(执行了两次函数b) function b(a, b) { var c = CryptoJS.enc.Utf8.parse(b) , d = CryptoJS.enc.Utf8.parse("0102030405060708") , e = CryptoJS.enc.Utf8.parse(a) , f = CryptoJS.AES.encrypt(e, c, { iv: d, mode: CryptoJS.mode.CBC }); return f.toString() } 需要传入参数a和b,实际上就是函数d中的参数d和g,参数g是固定的,参数d我们刚刚已经分析过了。 一开始分析的两个js逆向参数(params和encSecKey)的parmas我们已经清楚了加密过程(encText就是params)。 接着函数d继续看 h.encSecKey = c(i, e, f), encSecKey是通过函数c得到,函数c的代码如下: function c(a, b, c) { var d, e; return setMaxDigits(131), //131 => n的十六进制位数/2+3 d = new RSAKeyPair(b,"",c), e = encryptedString(d, a) } 函数c:通过RSA加密生成encSecKey值。 OK,JS逆向加密分析的过程就完成了。 03 小结 辰哥在本文中主要讲解了『JS逆向AES加密』反爬,并以某抑云获取歌曲真实播放地址为例去实战演示分析。

优秀的个人博客,低调大师

网易云音乐热评爬虫(一): 反编译加密参数

由于网易云音乐大部分请求做了混淆加密处理,因此直接用requests请求是行不通。本文以获取歌曲全部评论为例,通过分析网易云的加密过程,来反编译构造加密参数。下面主要介绍下用Python实现加密参数的构造,并获取歌曲的全部评论。 一、了解加密过程 1.1 通过观察网络请求 发现如下接口包含所要的数据。包含该页最新评论,以及所有热评 再看它评论的参数,着实让人有点懵逼 很多人看见这一串字符,可能简单看下前后接口有没数据就放弃了。好了,不卖关子。这章分析下整个参数的加密过程,实现最终模拟请求拿到数据。 1.2 找请求参数 可以看的到,它的参数有两个,一个是params,一个是encSecKey并且都是经过加密的,我们就要分析它在js中的位置(F12打开source搜索encSecKey) 进入js内部,经过断点调试发现这里就是生成最终参数的地方 1.3 观察参数变化 模拟不同分页请求,观察变化。效果如下图: 对比参数变化,得出参数构成: csrf_token :始终空字符串 cursor :第一页默认-1;请求下一页时该参数为上一页最后一条评论时间戳(防止数据重复) offset :移动评论数 orderType :默认1 pageNo :页码 pageSize :默认20 rid : R_SO_4_ + 歌曲ID threadId :R_SO_4_ + 歌曲ID 自此,我们已经知道整个参数的构成,接下来就看下网易云是如何进行参数加密的 二、分析加密函数 通过断点已经知道,下面这段js代码为我们分析的重点 var bZj0x = window.asrsea(JSON.stringify(i2x), bkk0x(["流泪", "强"]), bkk0x(YS7L.md), bkk0x(["爱心", "女孩", "惊恐", "大笑"])); e2x.data = j2x.cr3x({ params: bZj0x.encText, encSecKey: bZj0x.encSecKey }) 只要把bZj0x解出来就ok了,这里主要分析几个函数 2.1 JSON.stringify(i2x) 断点调制找到i2x返回内容 就是上文分析的整个字典参数 csrf_token: "" cursor: "1610076350235" offset: "40" orderType: "1" pageNo: "2" pageSize: "20" rid: "R_SO_4_1807537867" threadId: "R_SO_4_1807537867" 2.2bkk0x函数 bkk0x(["流泪", "强"]), bkk0x(YS7L.md), bkk0x(["爱心", "女孩", "惊恐", "大笑"]),都用到了同一个函数,这里就看下bkk0x函数内部实现是怎样的 var bkk0x = function(cJj8b) { var m2x = []; j2x.bf2x(cJj8b, function(cJi8a) { m2x.push(YS7L.emj[cJi8a]) }); return m2x.join("") } 等同于python写法 def get_bq_n1x(keys): m0x = [] for key in keys: m0x.append(emj[key]) return ''.join(m0x) YS7L.emj是一个固定的字典 YS7L.emj = { "色": "00e0b", "流感": "509f6", "这边": "259df", "弱": "8642d", "嘴唇": "bc356", "亲": "62901", "开心": "477df", "呲牙": "22677", "憨笑": "ec152", "猫": "b5ff6", "皱眉": "8ace6", "幽灵": "15bb7", "蛋糕": "b7251", "发怒": "52b3a", "大哭": "b17a8", "兔子": "76aea", "星星": "8a5aa", "钟情": "76d2e", "牵手": "41762", "公鸡": "9ec4e", "爱意": "e341f", "禁止": "56135", "狗": "fccf6", "亲亲": "95280", "叉": "104e0", "礼物": "312ec", "晕": "bda92", "呆": "557c9", "生病": "38701", "钻石": "14af6", "拜": "c9d05", "怒": "c4f7f", "示爱": "0c368", "汗": "5b7a4", "小鸡": "6bee2", "痛苦": "55932", "撇嘴": "575cc", "惶恐": "e10b4", "口罩": "24d81", "吐舌": "3cfe4", "心碎": "875d3", "生气": "e8204", "可爱": "7b97d", "鬼脸": "def52", "跳舞": "741d5", "男孩": "46b8e", "奸笑": "289dc", "猪": "6935b", "圈": "3ece0", "便便": "462db", "外星": "0a22b", "圣诞": "8e7", "流泪": "01000", "强": "1", "爱心": "0CoJU", "女孩": "m6Qyw", "惊恐": "8W8ju", "大笑": "d" } YS7L.md是一个固定的数据 YS7L.md = ["色", "流感", "这边", "弱", "嘴唇", "亲", "开心", "呲牙", "憨笑", "猫", "皱眉", "幽灵", "蛋糕", "发怒", "大哭", "兔子", "星星", "钟情", "牵手", "公鸡", "爱意", "禁止", "狗", "亲亲", "叉", "礼物", "晕", "呆", "生病", "钻石", "拜", "怒", "示爱", "汗", "小鸡", "痛苦", "撇嘴", "惶恐", "口罩", "吐舌", "心碎", "生气", "可爱", "鬼脸", "跳舞", "男孩", "奸笑", "猪", "圈", "便便", "外星", "圣诞"] 所以整个window.asrsea的参数都是可以得到的了,下面看下 window.asrsea()查看这个函数执行了什么操作 2.3window.asrsea() function a(a) { var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = ""; for (d = 0; a > d; d += 1) e = Math.random() * b.length, e = Math.floor(e), c += b.charAt(e); return c } function b(a, b) { var c = CryptoJS.enc.Utf8.parse(b) , d = CryptoJS.enc.Utf8.parse("0102030405060708") , e = CryptoJS.enc.Utf8.parse(a) , f = CryptoJS.AES.encrypt(e, c, { iv: d, mode: CryptoJS.mode.CBC }); return f.toString() } function c(a, b, c) { var d, e; return setMaxDigits(131), d = new RSAKeyPair(b,"",c), e = encryptedString(d, a) } function d(d, e, f, g) { var h = {} , i = a(16); return h.encText = b(d, g), h.encText = b(h.encText, i), h.encSecKey = c(i, e, f), h } function e(a, b, d, e) { var f = {}; return f.encText = c(a + e, b, d), f } window.asrsea = d 可以看到window.asrsea = d,所以我们要执行的就是d这个函数,主要执行3个操作 a(16),生成16位随机数 进行两次AES加密得到h.encText 通过位移等一系列运算生成h.encSecKey 三、Python实现相同的加密算法 """ 网易云请求参数反编译工具 :主要断点观察js,改为python实现 """ emj = { "色": "00e0b", "流感": "509f6", "这边": "259df", "弱": "8642d", "嘴唇": "bc356", "亲": "62901", "开心": "477df", "呲牙": "22677", "憨笑": "ec152", "猫": "b5ff6", "皱眉": "8ace6", "幽灵": "15bb7", "蛋糕": "b7251", "发怒": "52b3a", "大哭": "b17a8", "兔子": "76aea", "星星": "8a5aa", "钟情": "76d2e", "牵手": "41762", "公鸡": "9ec4e", "爱意": "e341f", "禁止": "56135", "狗": "fccf6", "亲亲": "95280", "叉": "104e0", "礼物": "312ec", "晕": "bda92", "呆": "557c9", "生病": "38701", "钻石": "14af6", "拜": "c9d05", "怒": "c4f7f", "示爱": "0c368", "汗": "5b7a4", "小鸡": "6bee2", "痛苦": "55932", "撇嘴": "575cc", "惶恐": "e10b4", "口罩": "24d81", "吐舌": "3cfe4", "心碎": "875d3", "生气": "e8204", "可爱": "7b97d", "鬼脸": "def52", "跳舞": "741d5", "男孩": "46b8e", "奸笑": "289dc", "猪": "6935b", "圈": "3ece0", "便便": "462db", "外星": "0a22b", "圣诞": "8e7", "流泪": "01000", "强": "1", "爱心": "0CoJU", "女孩": "m6Qyw", "惊恐": "8W8ju", "大笑": "d" } md = ["色", "流感", "这边", "弱", "嘴唇", "亲", "开心", "呲牙", "憨笑", "猫", "皱眉", "幽灵", "蛋糕", "发怒", "大哭", "兔子", "星星", "钟情", "牵手", "公鸡", "爱意", "禁止", "狗", "亲亲", "叉", "礼物", "晕", "呆", "生病", "钻石", "拜", "怒", "示爱", "汗", "小鸡", "痛苦", "撇嘴", "惶恐", "口罩", "吐舌", "心碎", "生气", "可爱", "鬼脸", "跳舞", "男孩", "奸笑", "猪", "圈", "便便", "外星", "圣诞"] def get_bq_n1x(keys): m0x = [] for key in keys: m0x.append(emj[key]) return ''.join(m0x) def __get_random_str(): """ Returns:16位的随机字符串 """ str_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" random_str = "" for i in range(16): index = random.randint(0, len(str_set) - 1) random_str += str_set[index] return random_str arg2 = get_bq_n1x(["流泪", "强"]) arg3 = get_bq_n1x(md) arg4 = get_bq_n1x(["爱心", "女孩", "惊恐", "大笑"]) random_str = __get_random_str() def __aes_encrypt(text, key): """ 获取到ASW加密后的数据 Args: text: 首先CBC加密方法,text必须位16位数据 key: 加密的key Returns:加密后的字符串 """ # 加密或者解密的初始向量(16位) iv = "0102030405060708" # 不是16的倍数则填充 pad = 16 - len(text) % 16 if isinstance(text, str): text = text + pad * chr(pad) else: text = text.deocde("utf-8") + pad * chr(pad) aes = AES.new(key=bytes(key, encoding="utf-8"), mode=2, iv=bytes(iv, encoding="utf-8")) res = aes.encrypt(bytes(text, encoding="utf-8")) res = base64.b64encode(res).decode("utf-8") return res def __get_enc_text(arg1): """ 对称加密后的参数 Args: arg1:加密参数 Returns: """ enc_text = __aes_encrypt(arg1, arg4) enc_text = __aes_encrypt(enc_text, random_str) return enc_text def __get_enc_sec_key(): """ 对称加密密钥 通过查看js代码,获取encSecKey """ # 随机字符串逆序排列 text = random_str[::-1] rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(arg2, 16) % int(arg3, 16) return format(rs, 'x').zfill(256) def linux_encrypt(text): # print(text) return text def get_form_data(text, method=''): """ 反编译生成 请求的form-data参数 Args: text: 跟踪js,自己组装参数 method: 方法 Returns:form-data参数 """ """ """ if method == 'linux': return linux_encrypt(text) text = str(text) return {"params": __get_enc_text(text), "encSecKey": __get_enc_sec_key()} 四、模拟请求歌曲评论 只要加密过程知道了,其实很多接口都可以模拟请求,此文仅供学习。 最终执行效果如下图:

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册