官网
中文文档:DrissionPage官网
一、为什么使用自动化?
1. 个人考虑
必须要承认一点,在各大厂商爬虫和反爬的策略不断升级迭代,逆向的成本逐步增加,逆向时间长,复杂度高等。自动化则可以间接规避掉环境,签名等加密参数的破解,逆向经常被各种网站埋藏的蜜罐参数,可以请求,但确一不小心就中招了,让网站一眼就能知道你不是一个人!
2. 时间成本
3. 法律风险
4. 不足
显而易见的慢,和消耗大量资源,所以对紧急任务做一个快速上线是个不错的选择。
二、为什么选择 DrissionPage
1. 优雅
语法简介,代码量少,对新手友好
既能控制浏览器,也能收法数据包(和requests那般丝滑)
2. 特征
1) selenium 有webdrive特征,driisionpage 没有webdrive特征
2) driisionpage基于cdp协议(其实selenium 4.0版本以后也支持了)
什么是cpd请参考
Chrome DevTools 协议
浏览器自动化必须知道CDP协议_chrome cdp-CSDN博客
三、开始
1. 下载
当前学习的版本 DrissionPage 4.1.0.12
pip install DrissionPage==4.1.0.12
2. 使用
from DrissionPage import Chromium, ChromiumPage
browser = Chromium()
tab = browser.latest_tab
tab.get("http://baidu.com")
四、滑动
滑动验证码的一些使用案例,配合ddddocr即可完成一些简单的滑动
page.actions.hold 按住鼠标左键不放
page.actions.move 移动
page.actions.release 松开鼠标
下面是一些核心代码。包括了如何使用ddddocr计算坐标,计算滑动轨迹,和自动化移动的实现
import time
import ddddocr
import random
from DrissionPage import ChromiumPage
import os
import shutil
class SlideCaptchaSolver:
def __init__(self):
self.page = ChromiumPage()
@staticmethod
def get_distance_by_ddddocr():
"""使用ddddocr计算缺口距离"""
det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
with open('./img/target.png', 'rb') as f:
target_bytes = f.read()
with open('./img/background.png', 'rb') as f:
background_bytes = f.read()
res = det.slide_match(target_bytes, background_bytes)
x_distance = res["target"][0]
return x_distance
@staticmethod
def get_tracks(distance):
"""滑块的运动轨迹"""
value = round(random.uniform(0.55, 0.75), 2)
v, t, sum = 0, 0.3, 0
plus = []
mid = distance * value
while sum < distance:
if sum < mid:
a = round(random.uniform(2.5, 3.5), 1)
else:
a = -round(random.uniform(2.0, 3.0), 1)
s = v * t + 0.5 * a * (t ** 2)
v = v + a * t
sum += s
plus.append(round(s))
reduce = [-6, -4, -6, -4]
return {'plus': plus, 'reduce': reduce}
def move_to_gap(self, slide_ele, tracks):
self.page.actions.hold(f"{slide_ele}") # 此方法用于按住鼠标左键不放,按住前可先移动到元素上
# 使鼠标相对当前位置移动若干距离
for track in tracks['plus']:
self.page.actions.move(
offset_x=track,
offset_y=round(random.uniform(1.0, 3.0), 0),
duration=.1
)
time.sleep(0.5)
self.page.actions.release(f"{slide_ele}") # 此方法用于释放鼠标左键,释放前可先移动到元素上。
ddddocr 是可以直接传入bytes ,可以不用下载图片
target_bytes = self.page.ele('.shumei_captcha_loaded_img_fg').src()
background_bytes = self.page.ele('.shumei_captcha_loaded_img_bg').src()
det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
res = det.slide_match(target_bytes, background_bytes)
五、获取show_root
# !/usr/bin/env python
# -*- coding: UTF-8 -*-
# @project :爬虫
# @author :zhy
# @date :2024-12-31 12:36
from DrissionPage import Chromium
browser = Chromium()
tab = browser.latest_tab
tab.get('https://ygp.gdzwfw.gov.cn/#/44/new/jygg/v3/A?noticeId=0a69a67b775c4690b1c49d02700c5048&projectCode=X44020008320002o32nn&bizCode=3C14&siteCode=440200&publishDate=20241231121903&source=%E9%9F%B6%E5%85%B3%E5%B8%82%E5%85%AC%E5%85%B1%E8%B5%84%E6%BA%90%E4%BA%A4%E6%98%93%E5%B9%B3%E5%8F%B0&titleDetails=%E5%B7%A5%E7%A8%8B%E5%BB%BA%E8%AE%BE&classify=A02&nodeId=1864880096317337601')
# html = tab.ele('xpath://div[@class="richtext"]/div').html
# print(html)
# out: <div data-v-0b057b9b=""></div>
html = tab.ele('xpath://div[@class="richtext"]/div').shadow_root
print(html)
# out: <ShadowRoot in <ChromiumElement div data-v-0b057b9b=''>>
print(html.ele('xpath://p[12]').text)
六、多线程
# !/usr/bin/env python
# -*- coding: UTF-8 -*-
# @project :爬虫
# @author :zhy
# @date :2024-12-31 12:36
from threading import Thread
from DrissionPage import ChromiumPage
from DataRecorder import Recorder
def collect(tab, recorder, title):
"""用于采集的方法
:param tab: ChromiumTab 对象
:param recorder: Recorder 记录器对象
:param title: 类别标题
:return: None
"""
num = 1 # 当前采集页数
while True:
# 遍历所有标题元素
for i in tab.eles('.title project-namespace-path'):
# 获取某页所有库名称,记录到记录器
recorder.add_data((title, i.text, num))
# 如果有下一页,点击翻页
btn = tab('@rel=next', timeout=2)
if btn:
btn.click(by_js=True)
tab.wait.load_start()
num += 1
# 否则,采集完毕
else:
break
def main():
# 新建页面对象
page = ChromiumPage()
url = 'https://www.xiaohongshu.com/explore'
# 第一个标签页访问网址
page.get('https://www.xiaohongshu.com/explore')
# 获取第一个标签页对象
tab1 = page.get_tab()
# 新建一个标签页并访问另一个网址
tab2 = page.new_tab('https://gitee.com/explore/machine-learning')
# 获取第二个标签页对象
tab2 = page.get_tab(tab2)
# 新建记录器对象
recorder = Recorder('data.csv')
# 多线程同时处理多个页面
Thread(target=collect, args=(tab1, recorder, 'python')).start()
Thread(target=collect, args=(tab2, recorder, 'java')).start()
if __name__ == '__main__':
main()