Python爬虫-Selenium库解决滑动验证与webdriver被发现的问题
1、前言
Selenium是一个自动化测试工具,也可以用于Web爬取。它可以控制浏览器并模拟人类操作,从而避免被反爬虫检测。
2、环境准备
2.1、安装selenium库
可以直接通过命令安装
pip install selenium
或者使用IDE安装
2.2、安装chromedriver
Selenium支持多种浏览器,包括ie、Firefox、Chrome等等。不同的浏览器与Selenium之间进行通信的载体不同,ChromeDriver就是Chrome浏览器与Selenium进行通信的载体。
下载地址如下:
1、http://chromedriver.storage.googleapis.com/index.html
2、https://npm.taobao.org/mirrors/chromedriver/
安装与自己的Chrome浏览器对应的版本,版本查看方式如下:
浏览器中输入chrome://version/
我下载的下图这个版本,小版本之间有差异影响不会很大
解压出来后将chromedriver.exe
放到和代码相同的路径,当然你可以自己随便放到一个地方,然后在电脑环境变量里添加这个路径就行,如果不想修改环境变量,则可以直接在代码里指定路径
chrome_driver = './chromedriver.exe'
driver = webdriver.Chrome(executable_path=chrome_driver)
3、Selenium使用
以前程无忧网
为例,搜索职位内容为大数据
通过网页源代码调试可以获取url地址如下:https://we.51job.com/api/job/search-pc?api_key=51job&keyword=%E5%A4%A7%E6%95%B0%E6%8D%AE&searchType=2&function=&industry=&jobArea=000000&jobArea2=&landmark=&metro=&salary=&workYear=°ree=&companyType=&companySize=&jobType=&issueDate=&sortType=0&pageNum=1&requestId=&pageSize=500&source=1&accountId=&pageCode=sou%7Csou%7Csoulb
&keyword=%E5%A4%A7%E6%95%B0%E6%8D%AE,表示大数据,修改这个参数可以爬取不同的职位
页码信息:&pageNum=1,修改此参数可以实现翻页
职位显示数量信息:&pageSize=20,可以使得每一页内容更多
如何获取的该地址参考文章:Python爬虫-Ajax网页爬取过程
手动打开该网页后,发现有滑动访问验证
这个时候便需要用到Selenium库了。
3.1、解决滑动验证
首先要知道这个滑块的位置,以及它的长度
通过下面代码自动化进行滑块验证:
from selenium import webdriver
from selenium.webdriver import ActionChains
import time
def main():
url = 'https://we.51job.com/api/job/search-pc?api_key=51job&keyword=%E5%A4%A7%E6%95%B0%E6%8D%AE&searchType=2&function=&industry=' \
'&jobArea=000000&jobArea2=&landmark=&metro=&salary=&workYear=°ree=&companyType=&companySize=&jobType=&issueDate=' \
'&sortType=0&pageNum=1&requestId=&pageSize=500&source=1&accountId=&pageCode=sou%7Csou%7Csoulb'
chrome_driver = './chromedriver.exe'
driver = webdriver.Chrome(executable_path=chrome_driver)
driver.get(url)
time.sleep(1)
# 找到需要滑动的滑块元素
slider = driver.find_element_by_xpath('//div[@class="nc_bg"]')
# 创建操作链
action_chains = ActionChains(driver)
# 将鼠标移动到滑块上
action_chains.move_to_element(slider)
# 模拟按下鼠标左键并保持不松开
action_chains.click_and_hold()
# 移动鼠标使滑块达到目标位置
action_chains.move_by_offset(300, 0)
# 松开鼠标左键
action_chains.release()
# 执行操作链
action_chains.perform()
time.sleep(10)
html = driver.page_source
driver.quit()
print(html)
if __name__ == '__main__':
main()
此时发现验证失败。
3.2、解决webdriver被发现
最开始出现验证失败时怀疑是代码操作时速度太快、轨迹不对,但是最后试过人为在程序打开那个页面去滑动验证也不行,所以应该是网站检测出来了webdriver
。
因为使用Selenium时,它在运行过程中会暴露出一些预定义的JavaScript变量(特征字符串),如window.navigator.webdriver
,在非Selenium环境下为false
,在Selenium环境下为true
。
非Selenium环境:
Selenium环境
解决方法如下:
chrome_driver = './chromedriver.exe'
options = webdriver.ChromeOptions()
options.add_experimental_option('useAutomationExtension', False)
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(chrome_options=options,executable_path=chrome_driver)
# webdriver防屏蔽
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => false
})
"""
})
useAutomationExtension
为False
和excludeSwitches
为['enable-automation']
。这些选项旨在防止Chrome检测到自动化测试,并阻止它弹出警告框或限制自动化操作。
execute_cdp_cmd
通过执行CDP命令(Chrome DevTools协议)来向页面注入JavaScript代码,该代码会覆盖navigator.webdriver属性,以隐藏浏览器正在运行自动化测试的标志。
options.add_argument("--disable-blink-features=AutomationControlled")
该行代码会将禁用Chrome自动化控制功能的选项添加到ChromeOptions对象中,并在创建ChromeDriver实例时应用该选项,以确保自动化测试可以稳定地运行而不被检测到。
3.3、最终效果
完整代码如下:
from selenium import webdriver
from selenium.webdriver import ActionChains
import time
def main():
url = 'https://we.51job.com/api/job/search-pc?api_key=51job&keyword=%E5%A4%A7%E6%95%B0%E6%8D%AE&searchType=2&function=&industry=' \
'&jobArea=000000&jobArea2=&landmark=&metro=&salary=&workYear=°ree=&companyType=&companySize=&jobType=&issueDate=' \
'&sortType=0&pageNum=1&requestId=&pageSize=500&source=1&accountId=&pageCode=sou%7Csou%7Csoulb'
chrome_driver = './chromedriver.exe'
options = webdriver.ChromeOptions()
options.add_experimental_option('useAutomationExtension', False)
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(chrome_options=options,executable_path=chrome_driver)
# webdriver防屏蔽
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => false
})
"""
})
driver.get(url)
time.sleep(1)
# 找到需要滑动的滑块元素
slider = driver.find_element_by_xpath('//div[@class="nc_bg"]')
# 创建操作链
action_chains = ActionChains(driver)
# 将鼠标移动到滑块上
action_chains.move_to_element(slider)
# 模拟按下鼠标左键并保持不松开
action_chains.click_and_hold()
# 移动鼠标使滑块达到目标位置
action_chains.move_by_offset(300, 0)
# 松开鼠标左键
action_chains.release()
# 执行操作链
action_chains.perform()
time.sleep(10)
html = driver.page_source
driver.quit()
print(html)
if __name__ == '__main__':
main()
如果不想要程序去打开浏览器界面,希望操作全部后台执行,可以使用静默模式
from selenium import webdriver
from selenium.webdriver import ActionChains
import time
def main():
url = 'https://we.51job.com/api/job/search-pc?api_key=51job&keyword=%E5%A4%A7%E6%95%B0%E6%8D%AE&searchType=2&function=&industry=' \
'&jobArea=000000&jobArea2=&landmark=&metro=&salary=&workYear=°ree=&companyType=&companySize=&jobType=&issueDate=' \
'&sortType=0&pageNum=1&requestId=&pageSize=500&source=1&accountId=&pageCode=sou%7Csou%7Csoulb'
options = webdriver.ChromeOptions()
# selenium静默执行(无浏览器界面)
options.add_argument('headless')
options.add_experimental_option('useAutomationExtension', False)
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_argument("--disable-blink-features=AutomationControlled")
chrome_driver = './chromedriver.exe'
driver = webdriver.Chrome(chrome_options=options,executable_path=chrome_driver)
# webdriver防屏蔽
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => false
})
"""
})
driver.get(url)
time.sleep(1)
# 找到需要滑动的滑块元素
slider = driver.find_element_by_xpath('//div[@class="nc_bg"]')
# 创建操作链
action_chains = ActionChains(driver)
# 将鼠标移动到滑块上
action_chains.move_to_element(slider)
# 模拟按下鼠标左键并保持不松开
action_chains.click_and_hold()
# 移动鼠标使滑块达到目标位置
action_chains.move_by_offset(300, 0)
# 松开鼠标左键
action_chains.release()
# 执行操作链
action_chains.perform()
time.sleep(10)
html = driver.page_source
driver.quit()
print(html)
if __name__ == '__main__':
main()
这样所有的操作都会在后台运行。