引入
在爬虫程序中,常常会遇到验证码校验的关卡,人工识别不仅慢而且很费精力,使用打码平台就成了高效,省时且便利的选择。
本次案例对于高清资源库1080zyk.com进行爬虫采集,使用超级鹰验证码识别(chaojiying.com)和python的requests库具体实现,类似的第三方打码库还有云打码,tt图鉴
,ddddorc
库等
代码实现
首先我们对网页进行分析,通过键入搜索框,并点击搜索按钮,F12中的网络接口可以找到,发起了两次请求
- post请求,将搜索框里的内容通过表单数据data发送给服务器
- get请求,返回的是验证码的图片
所以我们先编写如下代码,将图片保存本地,使用Session对象是为了保证验证码和请求是同一次会话
import requests
# 爬取优质资源网
session = requests.Session()
urls = {
"data": "http://www.1080zyk.com/index.php?m=vod-search",
"yanzenma": "https://www.1080zyk.com/inc/common/code.php?a=search&s=",
}
for key, url in urls.items():
if key == "data":
data = {"wd": "python", "submit": "search"}
response = session.post(url, data=data)
print(response.text)
elif key == "yanzenma":
response = session.get(url)
# response是一张图片
with open("./yanzenma.jpg", "wb") as f:
f.write(response.content)
print("验证码已保存到yanzenma.jpg")
超级鹰平台的使用
然后登陆到超级鹰打码平台,下载相应语言的接口示例
把python源文件解压到项目目录下,修改里面的参数,自己去超级鹰网站生成软件id,填入替换96001
导入类
在你的爬虫文件中导入超级鹰类,替换参数和图片地址,原本打印出来的是一个字典,我们取他的pic_str
值
可以看到,最后获取到了正确的验证码值
JavaScript逆向
检查验证码页面,发现主要内容是一段js代码实现检验功能,于是,我们把这段代码给复制下来,交给fittencode
解释.
fittenCode插件
结果如下:
$(".ldg_verify_submit").click(() => {
const code = $(".mac_verify").val();
const type = $("#code_type").val();
$.get("/inc/ajax.php?ac=code_check&code=" + code + "&type=" + type + "&rnd=" + Math.random(), function (r) {
const data = JSON.parse(r);
if (data.code == 1) {
location.reload();
} else {
alert(data.msg);
}
});
})
帮我解释一下这段代码
这段代码是一个使用jQuery编写的JavaScript代码片段,主要功能是处理一个验证提交按钮的点击事件。以下是对这段代码的详细解释:
-
$(".ldg_verify_submit").click(() => { ... })
:- 这行代码监听类名为
ldg_verify_submit
的元素的点击事件。当该元素被点击时,执行箭头函数内的代码。
- 这行代码监听类名为
-
const code = $(".mac_verify").val();
:- 这行代码获取类名为
mac_verify
的元素的值,并将其存储在变量code
中。通常,这个元素可能是一个输入框,用户在这里输入验证码。
- 这行代码获取类名为
-
const type = $("#code_type").val();
:- 这行代码获取ID为
code_type
的元素的值,并将其存储在变量type
中。这个元素可能也是一个输入框或下拉菜单,用于选择验证码的类型。
- 这行代码获取ID为
-
$.get("/inc/ajax.php?ac=code_check&code=" + code + "&type=" + type + "&rnd=" + Math.random(), function (r) { ... })
:- 这行代码使用jQuery的
$.get
方法发送一个GET请求到服务器。请求的URL是/inc/ajax.php
,并附带以下查询参数:ac=code_check
:表示执行的操作是验证码检查。code=
+ code:传递用户输入的验证码。type=
+ type:传递验证码的类型。rnd=
+ Math.random():添加一个随机数,以避免浏览器缓存。
- 这行代码使用jQuery的
-
const data = JSON.parse(r);
:- 这行代码将服务器返回的JSON字符串解析为JavaScript对象,并存储在变量
data
中。
- 这行代码将服务器返回的JSON字符串解析为JavaScript对象,并存储在变量
-
if (data.code == 1) { location.reload(); } else { alert(data.msg); }
:- 这行代码检查解析后的
data
对象中的code
属性。如果code
等于1,表示验证成功,页面将重新加载(location.reload()
)。如果code
不等于1,表示验证失败,弹出一个警告框显示data.msg
中的错误信息(alert(data.msg)
)。
- 这行代码检查解析后的
总结来说,这段代码的功能是当用户点击验证提交按钮时,获取用户输入的验证码和验证码类型,然后通过AJAX请求将这些信息发送到服务器进行验证。根据服务器的响应,决定是重新加载页面(验证成功)还是显示错误信息(验证失败)。
于是我们将参数拼接,对https://www.1080zyk.com/inc/ajax.php?ac=code_check&code=3991&type=search&rnd=1
发起请求,最后得到响应数据为{"code":1,"msg":"ok"}
,然后reload页面,发现,可以正常获得响应,于是,补充下列代码
# 校验验证码url
url = f"http://www.1080zyk.com/inc/ajax.php?ac=code_check&code={code}&type=search&rnd={random.randint(100000, 999999)}"
response_code = session.get(url)
if response_code.json()["code"] == 1: # 注意,不是字符串1
print("验证码正确")
print(session.get(urls["data"]).text)
else:
print("验证码错误")
最后,加入选择下载项和保存本地的代码,就完成了
import random
import requests
import lxml.etree
from 超级鹰接口 import Chaojiying_Client
# 初始化会话
session = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
"Cookie": "_ga=GA1.1.838502423.1724576396; PHPSESSID=o15hha1hpqlbddfon13h85rt37; _ga_20DNV0Q96J=GS1.1.1724591590.4.1.1724591970.0.0.0",
}
urls = {
"data": "http://www.1080zyk.com/index.php?m=vod-search",
"yanzenma": "https://www.1080zyk.com/inc/common/code.php?a=search&s=",
}
def fetch_captcha():
response = session.get(urls["yanzenma"])
with open("./yanzenma.jpg", "wb") as f:
f.write(response.content)
print("验证码已保存到yanzenma.jpg")
def recognize_captcha():
chaojiying = Chaojiying_Client(
"","",1
) # 用户中心>>软件ID 生成一个替换 96001
im = open(
"./yanzenma.jpg", "rb"
).read() # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
result = chaojiying.PostPic(im, 1902).get(
"pic_str"
) # 1902 验证码类型 官方网站>>价格体系 3.4+版 print 后要加()
return result
def verify_captcha(code):
url = f"http://www.1080zyk.com/inc/ajax.php?ac=code_check&code={code}&type=search&rnd={random.randint(100000, 999999)}"
response_code = session.get(url)
return response_code.json()
def search_data():
data = {"wd": "你好", "submit": "search"}
response = session.post(urls["data"], data=data)
return response.text
def parse_data(html):
tree = lxml.etree.HTML(html, None)
base_xpath = "//div[@class='xing_vb']/ul/li"
items = tree.xpath(base_xpath)
nums = [
{"标题": 1, "类别": 2, "地区": 3, "评分": 4, "更新时间": 5},
{
"链接": "span[2]/a/@href",
"标题": "span[2]/a/text()",
"类别": "span[3]/text()",
"地区": "span[4]/text()",
"评分": "span[5]/text()",
"更新时间": "span[6]/text()",
},
]
index = 1
for item in items:
if index == 1:
for name, num in nums[0].items():
name_value = item.xpath(f"./span[{num}]/text()")[0]
print(name_value)
index += 1
else:
for name, path in nums[1].items():
name_value = item.xpath(f"./{path}")[0]
print(name_value)
def main():
fetch_captcha()
# code = recognize_captcha()
code = input("请输入验证码:")
result = verify_captcha(code)
if result["code"] == 1:
print("验证码正确")
html = search_data()
parse_data(html)
else:
print("验证码错误")
if __name__ == "__main__":
main()
后面发现,js中使用reload刷新页面,一开始没注意,所以使用简单的requests库满足不了,可以改用selenium操作