赞
踩
以某网站为例,要查看每条信息,需要点击查看后完成滑块验证码的跳过
本文主要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
三方库识别出需要拖拽的距离,详情见官方文档:
[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])
获取到正确的拖动距离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) #写入数据库或者导出为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()
前面的就不多说了,直接跳到图形验证码的问题。其实大同小异,定位到图片所对应的元素,再获取图片。
获取图片的方式有2种:
1.图片链接放在了网页信息中,这种类型的图片直接使用request去请求这个链接,再获取图片。
2.图片没有链接,直接使用selenium截图,再保存到本地。
获取到图片后,再完成图片验证码的识别。主要的有两个第三方库,
这个库目前是使用最广泛的,可以自训练模型。现成的个人感觉只适合白底黑字的图片验证码,准确度很高。不是白底黑字就不太行。
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()
这个库是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池子,一般都是网上买的,挺便宜的,基本上链接被断开了就切换一下,用到的频率也不高
proxy_ip = '动态ip'
#启动浏览器时使用add_argument添加动态ip元素
options.add_argument('--proxy-server={}'.format(proxy_ip))
driver = webdriver.Chrome(options=options)
我每次使用时,是定义了一个函数,每次判断需要切换ip时,就调用该函数数调取api,然后获得一个临时ip进行请求
使用selenium时,可以看到浏览器上面有这个标记
有的网站会直接检测,使用selenium打开后,整个网页都是空白的。这个时候就要使用另一个库undetected_chromedriver
,这个库的使用方式和selenium一模一样,
import undetected_chromedriver as uc
#使用该库打开csdn
browser = uc.Chrome()
browser.get('https://www.csdn.net/')
可以看到使用,该方式打开的网页,没有显示chrome正受到自动软件控制。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。