当前位置:   article > 正文

python反爬-图像验证码与滑块验证码的跳过、反selenium检测,动态ip_网站的滑动验证码 如何爬虫绕过

网站的滑动验证码 如何爬虫绕过

python反爬-图像验证码与滑块验证码的跳过、反selenium检测,动态ip

一、滑块验证码的跳过

​ 以某网站为例,要查看每条信息,需要点击查看后完成滑块验证码的跳过

在这里插入图片描述

在这里插入图片描述

本文主要selenium模拟浏览器的方式,模拟网页操作,要获取所有信息就需要翻页,因此打开F12检查总页数对应的xpath节点,由下图可以观察到总页数的信息已经包含在了html网页上,因此先使用BeautifulSoup获取该网页信息,获取总页数,以便执行翻页的循环.

在这里插入图片描述

先通过BeautifulSoup获取总页码,需要观察上图页码所在位置对应的节点,页码参数对应的位置是text位置

在这里插入图片描述

import pandas as pd
from bs4 import BeautifulSoup
import requests
#获取验证码图片
url='该网页的url'
response= requests.get(url)
response.encoding='utf-8'
raw_data=response.text
 
soup = BeautifulSoup(raw_data, 'html.parser')

#先定位到class=key的div节点
key_content = soup.find('div',class_='key')
#再定位到align='center'的td表格
total_page=key_content.find('td',align='center')
#找到文本共.*条中间的数字
total_page_num=int(re.findall(r'当前 1/(\d+) 页',total_page.text)[0])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

找到总页码后,就可以开始执行循环,每次循环获取当前页面所有信息,然后就点击翻页。

先导入selenium所需要的库

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

下面进行每页信息的获取

获取每页信息需要点击查看按钮,因此我们需要定位到该按钮对应的节点,检查该按钮的元素,可以得到节点内容是

<input class="ck" type="button" onclick="doview('2407-410523-04-01-709156')" value="查看">

并且我们可以看到下一个查看按钮的节点内容除了onclick参数里面的内容其余都是一样的。因此我们在定位这个按钮的时候不要使用onclick参数定位,使用value和class参数一次性定位该页所有的查看按钮。

在这里插入图片描述

#打开网页
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=options)
driver.get(url)
  • 1
  • 2
  • 3
  • 4

观察页面可以发现,第一次进去的时候右下角有一个小弹窗,由于弹窗显示导致一页的所有按钮不会显示,因此先关闭这个弹窗
在这里插入图片描述

#定位元素后关闭弹窗
icon_element = driver.find_element(By.CSS_SELECTOR, 'img.demoIcon[οnclick="showOut()"]')
WebDriverWait(driver, 10).until(EC.element_to_be_clickable(icon_element))
icon_element.click()
  • 1
  • 2
  • 3
  • 4

定位元素的方法和刚才一样:打开F12后,点击这个按钮,然后再把鼠标移动到要定位的元素上点击,就可以显示该元素在网页中的位置

在这里插入图片描述

点击查看按钮后可以便会弹出滑块验证码,这时我们首先需要定位到滑块对应的元素

在这里插入图片描述

可以看到滑块元素的内容,因此定位滑块的代码是:

slider = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".slider-btn")))
  • 1

WebDriverWait(driver, 10).until()的作用是等待元素出现。

定位好元素后,则需要模拟拖拽操作,但首先需要知道应该拖拽的距离是多少。

本文使用的例子中,需要拖拽的距离已经隐藏在网页中,这种比较简单

还有一种比较麻烦的,滑块验证实际上就是三张图的组合,可以使用ddddocr三方库识别出需要拖拽的距离,详情见官方文档:

[ddddocr开源地址]: https://github.com/sml2h3/ddddocr/blob/master/README.md

其实很多滑块的正确答案会藏在网页中,比如这个网站,我打开F12的时候手动去拖动滑块按钮,拖动到正确位置的时候,显示是128px,再到这个节点附近去找包含了128px信息的元素,就找到了,于是直接定位该元素获得正确的拖动距离。

在这里插入图片描述

# 获取需要移动的距离
puzzle_lost_box = driver.find_element(By.CLASS_NAME,'puzzle-lost-box')
style_attribute = puzzle_lost_box.get_attribute('style')
left_value = [s.split(':')[1].strip() for s in style_attribute.split(';') if 'left' in s][0]
move_distance = int(re.findall(r'-(\d+)px',left_value)[0])	
  • 1
  • 2
  • 3
  • 4
  • 5

获取到正确的拖动距离move_distance后,使用selenium模拟拖拽动作就好了

# 创建ActionChains对象,并模拟拖拽动作
action_chains = ActionChains(driver)
action_chains.click_and_hold(slider).move_by_offset(move_distance, 0).release().perform()
#释放鼠标完成拖拽动作
action_chains.release().perform()
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

可以看到已经完成了滑块验证,出来了所需信息,再获取这些信息就OK了,下面的就不多说了。详情见以下代码

#定位查看元素
driver_clicks = driver.find_elements(By.CSS_SELECTOR,'input.ck[value="查看"]')
for driver_click in driver_clicks:
    #等待查看元素可点击
    WebDriverWait(driver, 10).until(EC.element_to_be_clickable(driver_click))
    driver_click.click()
    # 定位到滑块
    slider = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".slider-btn")))

    # 获取需要移动的距离
    puzzle_lost_box = driver.find_element(By.CLASS_NAME,'puzzle-lost-box')
    style_attribute = puzzle_lost_box.get_attribute('style')
    left_value = [s.split(':')[1].strip() for s in style_attribute.split(';') if 'left' in s][0]
    move_distance = int(re.findall(r'-(\d+)px',left_value)[0])

    # 创建ActionChains对象,并模拟拖拽动作
    action_chains = ActionChains(driver)
    action_chains.click_and_hold(slider).move_by_offset(move_distance, 0).release().perform()
    action_chains.release().perform()

    # 等待滑块移动到正确位置数据出现
    table_element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CLASS_NAME, "div_one"))
    )
    # 这时table_element就是要找的<table class="tableone">元素
    # 进行后续操作,例如获取表格内容等
    tables = table_element.find_elements(By.CLASS_NAME, 'tableone')
    table_content = tables[0].get_attribute('innerHTML')
    table_soup = BeautifulSoup(table_content, 'html.parser')

    # 获取项目代码
    project_code = table_soup.find(id="jbxx_dm").text
    # 获取项目名称
    project_name = table_soup.find(id="jbxx_mc").text

    table_content = tables[1].get_attribute('innerHTML')
    table_content = "<table>" + table_content + "</table>"
    project_info=pd.read_html(table_content)
    project_info = project_info[0]
    #将第一行设置为字段名并删除第一行
    project_info.columns = project_info.iloc[0]
    project_info = project_info.drop(project_info.index[0])
    #将项目名称和代码作为新的列加入到该表
    project_info['项目名称'] = project_name
    project_info['项目代码'] = project_code

    #删除字段审批部门,审批文号
    project_info = project_info.drop(['审批部门','审批文号'],axis=1)

    #写入数据库或者导出为excel
    print(project_info)
    project_info=project_info.rename(columns={'项目名称': 'project_name',
                                              '项目代码': 'project_code',
                                              '审批事项': 'review_detail',
                                              '审批结果':'review_result',
                                              '审批时间':'review_time'})
    project_info['insert_time'] = datetime.datetime.now()

    project_info.to_excel(f'{project_name}.xlsx')

    #定位关闭按钮并点击
    close_button = driver.find_element(By.CLASS_NAME, 'layui-layer-close2')
    close_button.click()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

二、图片验证码的跳过

前面的就不多说了,直接跳到图形验证码的问题。其实大同小异,定位到图片所对应的元素,再获取图片。

获取图片的方式有2种:

1.图片链接放在了网页信息中,这种类型的图片直接使用request去请求这个链接,再获取图片。

2.图片没有链接,直接使用selenium截图,再保存到本地。

获取到图片后,再完成图片验证码的识别。主要的有两个第三方库,

(一)pytesseract库

这个库目前是使用最广泛的,可以自训练模型。现成的个人感觉只适合白底黑字的图片验证码,准确度很高。不是白底黑字就不太行。

在这里插入图片描述

import  pytesseract
from PIL import Image
pytesseract.pytesseract.tesseract_cmd = r'D:\Tesseract\tesseract.exe'  # 修改为你的Tesseract安装路径

'''中间打开浏览器的代码省略了'''

captcha_element = driver.find_element(By.ID, "guestbookCaptcha")
#定位到元素的位置和大小
location = captcha_element.location
size = captcha_element.size
driver.save_screenshot('screenshot.png')
x = location['x']
y = location['y']
width = size['width']
height = size['height']
screenshot = Image.open('screenshot.png')
#截图
captcha_image = screenshot.crop((x, y, x + width, y + height))

#调用pytesseract进行识别
captcha_code = pytesseract.image_to_string(captcha_image)
captcha_code = captcha_code[:4]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这个时候captcha_code的参数就是对应的验证码,再将验证码输入到对应框中,点击验证,即完成验证码的验证。

#定位到输入框元素
captcha_input_element = driver.find_element(By.ID, "captchaForInput")

# 输入验证码
captcha_input_element.send_keys(captcha_code)
# 使用显示等待来确保按钮已经加载
button = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "bt02")))

# 执行点击操作
button.click()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(二)ddddocr库

这个库是git上一个开源的库,我一般喜欢用这个,能够处理比较复杂的图片验证码。

在这里插入图片描述

像这种验证码,使用pytesseract库就识别不出来,但是这个库可以,使用起来也很简单

'''前面的省略了,直接跳到截图代码部分'''

#定位验证码图片元素位置
capcha_img=driver.find_element(By.CLASS_NAME,'verifyCode')
#对这个元素进行截图(就不用裁剪了)
capcha_img.screenshot('screenshot.png')

import ddddocr
ocr = ddddocr.DdddOcr()
#转化灰度图进行识别
f = open(r'screenshot.png', mode='rb')
img = f.read()
capcha_code = ocr.classification(img)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这个时候capcha_code就是验证码的字符串文本,然后再进行输入和后续操作。

三、动态ip

这个其实很简单,需要有一个动态ip池子,一般都是网上买的,挺便宜的,基本上链接被断开了就切换一下,用到的频率也不高

proxy_ip = '动态ip'
#启动浏览器时使用add_argument添加动态ip元素
options.add_argument('--proxy-server={}'.format(proxy_ip))
driver = webdriver.Chrome(options=options)
  • 1
  • 2
  • 3
  • 4

我每次使用时,是定义了一个函数,每次判断需要切换ip时,就调用该函数数调取api,然后获得一个临时ip进行请求

四、反selenium检测

使用selenium时,可以看到浏览器上面有这个标记

在这里插入图片描述

有的网站会直接检测,使用selenium打开后,整个网页都是空白的。这个时候就要使用另一个库undetected_chromedriver,这个库的使用方式和selenium一模一样,

import undetected_chromedriver as uc
#使用该库打开csdn
browser = uc.Chrome()
browser.get('https://www.csdn.net/')
  • 1
  • 2
  • 3
  • 4

可以看到使用,该方式打开的网页,没有显示chrome正受到自动软件控制。

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/946271
推荐阅读
相关标签
  

闽ICP备14008679号