爬虫之selenium
程序员文章站
2022-09-27 08:43:48
selenium基本操作 概念:基于浏览器自动化的模块 :基于手机自动化的模块的应用 环境的安装 跟爬虫之间的关联? 可以实现模拟登陆 便捷的捕获动态加载数据(可见即可得) 基本操作 导包: (web浏览器,driver驱动) 必须提供对应浏览器的驱动程序(谷歌,火狐...) "谷歌浏览器驱动下载地 ......
selenium基本操作
-
概念:基于浏览器自动化的模块
-
appnium
:基于手机自动化的模块的应用
-
-
环境的安装
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
-
跟爬虫之间的关联?
- 可以实现模拟登陆
- 便捷的捕获动态加载数据(可见即可得)
-
基本操作
-
导包:
from selenium import webdriver
(web浏览器,driver驱动) -
必须提供对应浏览器的驱动程序(谷歌,火狐...)
-
实例化一个浏览器对象
bro = webdriver.chrome(executable_path='./chromedriver.exe') # chrome 谷歌浏览器 executable_path 浏览器驱动路径
-
标签定位
- find系列的函数
-
标签对象.send_keys()
:向指定标签中录入数据 -
提交标签.click()
-
js
注入:浏览器对象.execute_script("js代码")
-
浏览器对象.page_source
:返回当前页面的页面源码数据,包含动态加载数据 -
关闭浏览器:
浏览器对象.quit()
-
-
缺点
- 爬取的效率比较低下
-
什么时候用selenium
- 动态加载的数据requests模块实在爬取不到,使用selenium
示例代码
- 登陆京东,搜索商品
from selenium import webdriver from time import sleep # 实例化浏览器对象 bro = webdriver.chrome(executable_path='./chromedriver.exe') # chrome 谷歌浏览器 executable_path 浏览器驱动地址 # 制定一些自动化的操作 # 发起请求 bro.get('https://www.jd.com') # 如何进行标签定位 search_tag = bro.find_element_by_id('key') # 向文本框中录入数据 search_tag.send_keys('mac pro') sleep(2) btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button') btn.click() sleep(2) # 注入js代码 bro.execute_script('window.scrollto(0,document.body.scrollheight)') sleep(2) # page_source :返回当前页面的页面源码数据,包含动态加载数据 print(bro.page_source) # 关闭浏览器 bro.quit()
案例:使用selenium捕获要药监总局的动态加载数据
- 该网站的数据是动态加载的,来测试selenium如何便捷的捕获动态加载数据
- 网址:
from selenium import webdriver from time import sleep from lxml import etree # 实例化浏览器对象 bro = webdriver.chrome(executable_path='./chromedriver.exe') # 发起请求 bro.get('http://125.35.6.84:81/xk/') sleep(1) # 第一页的页面源码数据 page_text = bro.page_source all_page_text = [page_text] for i in range(1,5): # 找到下一页对应的标签 a_tag = bro.find_element_by_xpath('//*[@id="pageito_next"]') # 对下一页的标签发起点击 a_tag.click() sleep(1) # page_source 获取当前页面的源码数据(涵动态加载) page_text = bro.page_source all_page_text.append(page_text) for page_text in all_page_text: tree = etree.html(page_text) # xpath解析到name对应的标签 li_lst = tree.xpath('//*[@id="gzlist"]/li') for li in li_lst: name = li.xpath('./dl/@title')[0] print(name) sleep(2) bro.quit()
动作链
动作链:一系列连续的动作
- 导包:
from selenium.webdriver import actionchains
-
nosuchelementexception
报错:没有定位到指定的标签- 定位的标签是存在于一张嵌套的子页面中,如果想定位之页面中的指定标签的话需要:
-
浏览器对象.switch_to.frame('iframe标签id的属性值')
:将当前浏览器页面切换到指定的子页面范围中
-
- 定位的标签是存在于一张嵌套的子页面中,如果想定位之页面中的指定标签的话需要:
- 针对指定的浏览器实例化一个动作链对象
action = actionchains(bro)
- 点击且长按指定的标签
action.click_and_hold(tagname)
- 偏移
-
action.move_by_offset(xoffset, yoffset)
一点一点偏移 action.move_to_element(to_element)
action.move_to_element_with_offset(to_element, xoffset, yoffset)
-
-
偏移.perform()
:动作链立即执行
示例代码
- 标签嵌套子页面中,
from selenium import webdriver from selenium.webdriver import actionchains from time import sleep bro = webdriver.chrome("./chromedriver.exe") bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable') # 标签定位 bro.switch_to.frame('iframeresult') div_tag = bro.find_element_by_id('draggable') # 需要使用actionchains定制好的行为动作 # 针对当前浏览器页面实例化了一个动作链对象 action = actionchains(bro) # 点击且长按一个指定的标签 action.click_and_hold(div_tag) for i in range(1,7): # 一点一点迁移 action.move_by_offset(10,15).perform() # perform() 是动作链立即执行 action.move_to_element action.move_to_element_with_offset sleep(0.5)
无头浏览器
- 概念:没有可视化界面的浏览器
- phantomjs无头浏览器,几乎不用了,停止更新维护了,现在不用了
谷歌无头浏览器
- 就是本机安装的谷歌浏览器,只是需要通过代码进行相关配置就可以变成无头浏览器
from selenium import webdriver from selenium.webdriver.chrome.options import options # 无头浏览器开整 # 实例化options对象 chrome_options = options() # 调用add_argument方法,进行自定义配置 chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') bro = webdriver.chrome(executable_path="./chromedriver.exe",chrome_options=chrome_options) bro.get('https://www.baidu.com') # 截屏 bro.save_screenshot('./1.png') print(bro.page_source)
规避检测
-
webserver是如何检测到我们的请求是否使用了
selenium
- 网站开发者工具consloe中注入js代码:
window.navigator.webdriver
- true:请求是基于selenium发起的(异常请求)
- undefined:请求是基于浏览器发起的(正常请求)
- 网站开发者工具consloe中注入js代码:
-
环境配置
-
本机谷歌浏览器的驱动程序所在的目录路径添加到环境变量中
-
使用本机谷歌的驱动程序开启一个浏览器
-
chrome.exe --remote-debugging-port=9222 --user-data-dir="d:\selenum\automationprofile"
9222:端口(任意空闲端口)
"d:\selenum\automationprofile":已经事先存在的一个空目录
-
-
使用托管机制
- consloe中注入js代码:window.navigator.webdriver,虽然会返回true,但不会提示请停用以开发者模式运行的扩展程序,相当于自己打开的浏览器
# 终端先运行如下代码 chrome.exe --remote-debugging-port=9222 --user-data-dir="d:\selenum\automationprofile" from selenium import webdriver from selenium.webdriver.chrome.options import options chrome_options = options() chrome_options.add_experimental_option('debuggeraddress','127.0.0.1:9222') # 代码托管打开的浏览器,不会实例化一个新的浏览器 driver = webdriver.chrome(executable_path="./chromedriver.exe",chrome_options=chrome_options) driver.get('http://www.taobao.com')
- 老版本的
selenium
规避检测的操作- 这个目前会被检测到
from selenium import webdriver from selenium.webdriver import chromeoptions option = chromeoptions() #实例化一个chromeoptions对象 option.add_experimental_option('excludeswitches', ['enable-automation']) #以键值对的形式加入参数 bro = webdriver.chrome(executable_path='./chromedriver.exe',options=option) #在调用浏览器驱动时传入option参数就能实现undefined
模拟登陆
12306模拟登陆
-
url:
-
分析:
- 识别的验证码图片必须通过截图获取验证码然后存储到本地
- 登陆操作和唯一的验证码图片一一对应
- 识别的验证码图片必须通过截图获取验证码然后存储到本地
-
基于超级鹰识别验证码登录,类型9004
# 超级鹰的包 import requests from hashlib import md5 class chaojiying_client(object): def __init__(self, username, password, soft_id): self.username = username password = password.encode('utf8') self.password = md5(password).hexdigest() self.soft_id = soft_id self.base_params = { 'user': self.username, 'pass2': self.password, 'softid': self.soft_id, } self.headers = { 'connection': 'keep-alive', 'user-agent': 'mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0)', } def postpic(self, im, codetype): """ im: 图片字节 codetype: 题目类型 参考 http://www.chaojiying.com/price.html """ params = { 'codetype': codetype, } params.update(self.base_params) files = {'userfile': ('ccc.jpg', im)} r = requests.post('http://upload.chaojiying.net/upload/processing.php', data=params, files=files, headers=self.headers) return r.json() def reporterror(self, im_id): """ im_id:报错题目的图片id """ params = { 'id': im_id, } params.update(self.base_params) r = requests.post('http://upload.chaojiying.net/upload/reporterror.php', data=params, headers=self.headers) return r.json() # 封装一个验证码识别的函数 def transform_code(imgpath,imgtype): chaojiying = chaojiying_client('超级鹰用户名', '超级鹰用户名对应的密码', '软件id') im = open(imgpath, 'rb').read() return chaojiying.postpic(im, imgtype)['pic_str'] # 模拟登陆实现代码 from time import sleep from pil import image # pip install pillow from selenium import webdriver from selenium.webdriver import actionchains # 实例化一个谷歌浏览器对象 bro = webdriver.chrome(executable_path="./chromedriver.exe") # 发起请求 bro.get('https://kyfw.12306.cn/otn/resources/login.html') # 登录页面第一个展示的是扫码,点击帐号密码登录 bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click() sleep(2) # 等待2秒,加载验证码图片 # 定位到用户名密码框,输入帐号密码 bro.find_element_by_id('j-username').send_keys('xxxxxxxx') # 12306用户名 bro.find_element_by_id('j-password').send_keys('********') # 12306用户名对应的密码 # 验证码的点击操作 bro.save_screenshot('./12306.png')# 将页面当作图片保存到本地 # 将验证码图片的标签定位到 img_tag = bro.find_element_by_id('j-loginimg') # 验证码的坐标和大小 location = img_tag.location size = img_tag.size # 裁剪的范围,这个根据截图自己情况调整,自己调试的(699, 284, 1015, 472) rangle = (int(location['x'])-65,int(location['y']),int(location['x']+size['width'])-49,int(location['y']+size['height'])) # 使用image类根据rangle裁剪范围进行验证码图片的裁剪 i = image.open('./12306.png') # bytes类型数据 frame = i.crop(rangle) # 验证码对应的二进制数据 frame.save('./code.png') img_coor = transform_code('./code.png',9004) # 返回坐标值 274,146|37,147 # 将坐标字符串转换为嵌套的列表 all_lst = [] # [[274,146],[37,147]...] if '|' in img_coor: lst_1 = img_coor.split("|") count_1 = len(lst_1) for i in range(count_1): xy_lst = [] x = int(lst_1[i].split(',')[0]) y = int(lst_1[i].split(',')[1]) xy_lst.append(x) xy_lst.append(y) all_lst.append(xy_lst) else: x = int(img_coor.split(',')[0]) y = int(img_coor.split(',')[1]) xy_lst = [] xy_lst.append(x) xy_lst.append(y) all_lst.append(xy_lst) for data in all_lst: # 每个data都是一个列表中有2个元素 x = data[0] y = data[1] # 实例化一个动作链,在指定范围(验证码标签范围),找到x,y坐标,点击,动作链立即执行 actionchains(bro).move_to_element_with_offset(img_tag,x,y).click().perform() # 执行一次等待0.5秒,防止过快 sleep(0.5) # 点击登录按钮,实现登录 bro.find_element_by_id('j-login').click() sleep(2) # 关闭浏览器 bro.quit()
上一篇: 如何从开发岗转型做架构师?