Python浏览器指纹反爬详解(包含案例)——blog10

目录

概述

案例实操

目标

分析

补充

开始

由此可以得到方法一:直接从api拿数据

方法二:伪装selenium.webdriver

测试

测试用HTML如下:

爬取失败——分析与思考

改进

最后附上使用selenium破解目标网站浏览器指纹的完整代码:

觉得有帮助的小伙伴还请点个关注


概述

浏览器指纹是由浏览器类型版本号操作系统屏幕分辨率时区插件字体等信息组合而成的唯一标识,可以用于区分不同的用户。通过比对请求中的浏览器指纹与真实用户的指纹进行对比,可以识别出爬虫请求并进行相应的处理,例如拒绝访问、验证码验证等,以保护网站的正常运行和数据的安全。

收集浏览器指纹

⬇️

分析浏览器指纹

⬇️

验证浏览器指纹

⬇️

判断处理

案例实操

目标

练习网页地址如下:

初识浏览器指纹:Selenium是如何被反爬的_H06_Python爬虫

打开该页面,和上期出的时间戳反爬教程一样:页面上储存了由NordPass发布的2022年全球最常用密码列表,我们训练的目标是使用selenium的webdriver成功获取其中的数据。

分析

F12打开检查,选择sources,网站已经预先加载好了一些项目,我们打开JS,发现是没有JS混淆的。

首先我们看一下第一句:

var user_agent = navigator.userAgent;
if ((!navigator.webdriver) & (navigator.plugins.length > 0) & (user_agent.indexOf('headless') < 0)) {
    console.log(navigator.webdriver);
    console.log(navigator.plugins.length);
    console.log(user_agent.indexOf('headless'));
    var timeStamp = Math.trunc(new Date().getTime() / 1000);
    var _md5 = md5(timeStamp);
    var s = btoa(`${timeStamp},${_md5}`);

他是取浏览器的一个user agent放到一个变量里面,做了一个判断,包括webdriver以及plugin的长度,还有就是看一下user agent里面有没有headless这样的关键词,如果没有,他就打印一下日志,然后开始取时间戳,取到秒(JS默认取出来是到毫秒的)

补充

关于时间戳反爬,可以看我之前的博客:

时间戳反爬详解

第六行.getTime()/1000,即是做了一个取整操作,然后对取整后的时间戳使用MD5加密,再把时间戳和MD5用英文逗号隔开,拼接成一个字符串,放置在变量s里面。

$.ajax({
        url: "/h06/api/" + s,
        type: "get",
        success: function (data) {
            if (data != null) {
                var dataContent = document.getElementById('dataContent');
                data.forEach((value, index) => {
                    var row = dataContent.insertRow();
                    var rankingCell = row.insertCell();
                    rankingCell.innerText = value.ranking;

                    var passwdCell = row.insertCell();
                    passwdCell.innerText = value.passwd;

                    var time_to_crackItCell = row.insertCell();
                    time_to_crackItCell.innerText = value.time_to_crack_it;

                    var used_countCell = row.insertCell();
                    used_countCell.innerText = value.used_count;

紧接着这里是用jquery的库,对这个H06进行一个请求操作,请求H06的api,方法是get,取戳来之后这个data如果不为空,那我们就开始按照ID来取这个网页的div,然后就开始遍历我们的JSON——一个一个地插入进页面。

开始

这样一来思路就很清晰了。

首先是相对固定的操作,导包,写一些基本信息:

# coding=utf-8
import base64
import hashlib
import time

import requests


base_url = 'http://www.spiderbuf.cn/h06'

myheaders = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36'}

经过上文的分析我们可以知道几个关键点:取时间戳、加密、get请求

由此可以得到方法一:直接从api拿数据

url = 'http://spiderbuf.cn/h06/api/'
timestamp = str(int(time.time()))
md5_hash = hashlib.md5()
md5_hash.update(timestamp.encode('utf-8'))
md5 = md5_hash.hexdigest()
s = ('%s,%s' % (timestamp, md5))
print(s)
payload = str(base64.b64encode(s.encode('utf-8')), 'utf-8')
print(payload)
html = requests.get(url + payload, headers=myheaders).text
print(html)
#将字符串转换为字典
dict_data = eval(html)
print(dict_data)
for item in dict_data:
    print(item)

运行解析出来,发现全部都是我们需要的字符串。

方法二:伪装selenium.webdriver

测试

第一步同样,导包,写一些基本信息:

# coding=utf-8
import time

from lxml import etree
from selenium import webdriver


base_url = 'http://www.spiderbuf.cn/h06'

myheaders = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36'}

首先写一段最基础的获取html的代码,然后使用selenium测试一下是否能得到想要的数据:

def getHTML(url,file_name=''):
    client = webdriver.Chrome()
    client.get(url)
    html = client.page_source
    #print(html)
    client.quit()
    
    if file_name != '':
        with open(file_name, 'w', encoding='utf-8') as f:
            f.write(html)
    return html

运行,看到selenium打开一个浏览器,但是里面的数据是空的……

html = getHTML(base_url, './data/h06/h06.html')
print(html)

看到它返回的HTML代码,下面的数据也是空的,也就是说,网站现在是检测到我们使用的是selenium,然后就被反爬了,不输出数据。

那么我们这时候就需要回头看一下,selenium是怎么被反爬的。

我们先写一个本地的测试用的HTML。

console.log(navigator.webdriver);
console.log(navigator.plugins.length);
console.log(user_agent.indexOf('headless'));

看一下我们之前在这个网页检查sources中看的JS,测试一下这三句话究竟做了什么。

测试用HTML如下:
<html>
<head>
    <title>test</title>
</head>
<body>
    <h2>test for m0_66653437's blog</h2>
    <script type="text/javascript">
        console.log(navigator.webdriver);
        console.log(navigator.plugins.length);
        console.log(user_agent.indexOf('headless'));
    </script>
</body>
</html>
        

我们看一下这里的判断究竟做了什么。

还是运行我们上文中的代码:

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument('headless')
options.set_capability('goog:loggingPrefs', {'browser': 'ALL'})
options.add_argument('--disable-blink-features=AutomationControlled')
client = webdriver.Chrome(options=options)
client.get('file:Users/dingyifan/Desktop/test.html')
print(client.page_source)
for i in client.get_log('browser'):
    print(i['message'])

client.quit()

(笔者webdriver没更新懒得弄了,这里就先不展示输出界面,直接上结论)

爬取失败——分析与思考

运行发现,上述HTML中输出部分第一句,检测我们是否使用webdriver发起请求,再者便是检测plungin插件个数以及ChromeOption的属性。

上述代码中,如果去掉:

options.add_argument('--disable-blink-features=AutomationControlled')

发现“console.log(navigator.webdriver);”输出的一个参数从False变成了True,这个值不一样了,这个值是干什么的?

这个值是检测现在的请求是不是用webdriver发起的,就是它会问你的浏览器,你是不是webdriver,他就老老实实回答:“我是!”

再者console.log(navigator.plugins.length);”输出结果会是0,那么这样他就知道你使用的是webdriver了,你使用的是爬虫。

于是下面的这句话可以直接写死:

options.add_argument('--disable-blink-features=AutomationControlled')

或者当ChromeOptions中出现“headless”关键词,也有可能被识别为爬虫:你都不打开我的页面,都不在看的,那你访问我的网址有集贸用?

改进

那么我们就把段代码加入到之前获取HTML的代码段中,看一下是否能返回我们需要的内容。

def getHTML(url,file_name=''):
    client = webdriver.Chrome()
    client.get(url)
    html = client.page_source
    print(html)
    client.quit()
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    options.set_capability('goog:loggingPrefs', {'browser': 'ALL'})  # 输出浏览器console 日志:console.log

    options.add_argument('--disable-blink-features=AutomationControlled')  # 改变navigator.webdriver 属性值

    client = webdriver.Chrome(options=options)
    client.get(url)
    print(client.page_source)
    html = client.page_source

    client.quit()

    if file_name != '':
        with open(file_name, 'w', encoding='utf-8') as f:
            f.write(html)
    return html

运行:

html = getHTML(base_url, './data/h06/h06.html')
print(html)

试一下,发现成功输出了我们想要的结果:

[{"ranking":1,"passwd":"password","time_to_crack_it":"\u003c 1 Second","used_count":4929113,"year":2022},{"ranking":2,"passwd":"123456","time_to_crack_it":"\u003c 1 Second","used_count":1523537,"year":2022},{"ranking":3,"passwd":"123456789","time_to_crack_it":"\u003c 1 Second","used_count":413056,"year":2022},

………………………………………………

最后附上使用selenium破解目标网站浏览器指纹的完整代码:
# coding=utf-8
from lxml import etree
from selenium import webdriver

base_url = 'http://www.spiderbuf.cn/h06'

myheaders = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36'}


def getHTML(url,file_name=''):
    client = webdriver.Chrome()
    client.get(url)
    html = client.page_source
    print(html)
    client.quit()
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    options.set_capability('goog:loggingPrefs', {'browser': 'ALL'})  # 输出浏览器console 日志:console.log

    options.add_argument('--disable-blink-features=AutomationControlled')  # 改变navigator.webdriver 属性值

    client = webdriver.Chrome(options=options)
    client.get(url)
    print(client.page_source)
    html = client.page_source

    client.quit()

    if file_name != '':
        with open(file_name, 'w', encoding='utf-8') as f:
            f.write(html)
    return html


def parseHTML(html,file_name=''):
    root = etree.HTML(html)
    trs = root.xpath('//tr')

    if file_name != '':
        f = open(file_name, 'w', encoding='utf-8')

    for tr in trs:
        tds = tr.xpath('./td')
        s = ''
        for td in tds:
            s = s + str(td.xpath('string(.)')) + '|'
            # s = s + str(td.text) + '|'
        print(s)
        if (s != '') & (file_name != ''):
            f.write(s + '\n')
    f.close()


if __name__ == '__main__':
    
    html = getHTML(base_url, './data/h06/h06.html')
    print(html)
    parseHTML(html, './data/h06/h06.txt')

觉得有帮助的小伙伴还请点个关注

后续会持续分享 免费、高质量 的高校相关以及Python学习文章

(拒绝AI水文章)

  • 51
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python指纹反爬是一种反爬虫技术,它通过识别请求中的特定特征指纹来检测和阻止爬虫。其中,JA3指纹是一种用于识别TLS客户端的指纹算法,可以在改变IP地址和User Agent(UA)的情况下仍然识别到请求的来源。 要在Python中修改JA3指纹,可以使用第三方库requests,并通过修改其源代码来实现。具体步骤如下: 1. 首先,安装requests库。可以使用pip命令运行以下命令来安装最新版本的requests: ```python pip install requests ``` 2. 导入requests库,并创建一个Session对象: ```python import requests session = requests.Session() ``` 3. 修改Session对象的headers属性,将请求头的User-Agent字段设置为自定义的值。这样可以隐藏默认的User-Agent,增加请求的隐蔽性: ```python session.headers['User-Agent'] = '自定义的User-Agent' ``` 4. 修改Session对象的TLS指纹(JA3指纹)。可以在网络上搜索到一些可以用于修改JA3指纹Python库或代码示例,如。根据具体情况选择合适的方法来修改JA3指纹。 5. 使用修改后的Session对象发送请求。可以使用Session对象的get()或post()方法发送HTTP请求,并获取响应内容: ```python response = session.get(url) ``` 通过以上步骤,我们可以在Python中使用requests库来修改JA3指纹,从而提高爬虫的隐蔽性。请注意,根据网站的反爬虫策略,可能还需要进行其他处理,如处理验证码、使用代理IP等措施来进一步提高爬虫的成功率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值