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])
找到总页码后,就可以开始执行循环,每次循环获取当前页面所有信息,然后就点击翻页。
先导入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
下面进行每页信息的获取
获取每页信息需要点击
查看
按钮,因此我们需要定位到该按钮对应的节点,检查该按钮的元素,可以得到节点内容是
<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)
观察页面可以发现,第一次进去的时候右下角有一个小弹窗,由于弹窗显示导致一页的所有按钮不会显示,因此先关闭这个弹窗
#定位元素后关闭弹窗
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()
定位元素的方法和刚才一样:打开F12后,点击这个按钮,然后再把鼠标移动到要定位的元素上点击,就可以显示该元素在网页中的位置
点击
查看
按钮后可以便会弹出滑块验证码,这时我们首先需要定位到滑块对应的元素
可以看到滑块元素的内容,因此定位滑块的代码是:
slider = WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,".slider-btn")))
WebDriverWait(driver, 10).until()
的作用是等待元素出现。
定位好元素后,则需要模拟拖拽操作,但首先需要知道应该拖拽的距离是多少。
本文使用的例子中,需要拖拽的距离已经隐藏在网页中,这种比较简单
还有一种比较麻烦的,滑块验证实际上就是三张图的组合,可以使用
ddddocr
三方库识别出需要拖拽的距离,详情见官方文档:
其实很多滑块的正确答案会藏在网页中,比如这个网站,我打开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])
获取到正确的拖动距离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()
可以看到已经完成了滑块验证,出来了所需信息,再获取这些信息就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)#写入数据库或者导出为excelprint(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()
二、图片验证码的跳过
前面的就不多说了,直接跳到图形验证码的问题。其实大同小异,定位到图片所对应的元素,再获取图片。
获取图片的方式有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]
这个时候
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()
(二)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)
这个时候capcha_code就是验证码的字符串文本,然后再进行输入和后续操作。
三、动态ip
这个其实很简单,需要有一个动态ip池子,一般都是网上买的,挺便宜的,基本上链接被断开了就切换一下,用到的频率也不高
proxy_ip ='动态ip'#启动浏览器时使用add_argument添加动态ip元素
options.add_argument('--proxy-server={}'.format(proxy_ip))
driver = webdriver.Chrome(options=options)
我每次使用时,是定义了一个函数,每次判断需要切换ip时,就调用该函数数调取api,然后获得一个临时ip进行请求
四、反selenium检测
使用selenium时,可以看到浏览器上面有这个标记
有的网站会直接检测,使用selenium打开后,整个网页都是空白的。这个时候就要使用另一个库
undetected_chromedriver
,这个库的使用方式和selenium一模一样,
import undetected_chromedriver as uc
#使用该库打开csdn
browser = uc.Chrome()
browser.get('https://www.csdn.net/')
可以看到使用,该方式打开的网页,没有显示chrome正受到自动软件控制。
版权归原作者 九七不会用python 所有, 如有侵权,请联系我们删除。