python Web抓取(二)selenium模块的使用、对浏览器的按键操作及错误处理
建议以下帖子:
教你在Windows上搭建Python+Selenium环境:https://blog.csdn.net/huilan_same/article/details/52888262
python webdriver 的异常:https://blog.csdn.net/huilan_same/article/details/52815047
Selenium库的使用:https://blog.csdn.net/weixin_36279318/article/details/79475388
以下是我满怀信心学习却被异常为所欲为的调戏但是坚持抵抗留下的充满逻辑的笔记
一、用selenium模块控制浏览器
安装selenium 3.1410
selenium能让用户通过Python直接控制浏览器,实际点击链接,填写登录信息,几乎就像一个人类与浏览器交互。这能比使用 Request 和 Beautiful Soup 模块完成更多的事情,能让你以更高级的方式和浏览器交互,但是也有一个确定,比如当你只是想下载一个文件时,前者就有些复杂,并且难以在后台运行
安装针对chrome的浏览器驱动(注意版本):http://selenium-release.storage.googleapis.com/index.html
1.1启动selenium控制的浏览器
以 form selenium import webdriver 来导入webderiver模块
>>> from selenium import webdriver >>> browser=webdriver.Chrome() >>> browser.get('http://www.baidu.com') >>> browser.quit()#退出
1.2在页面中寻找元素
Webdriver对象有好几种方法,用于在页面中寻找元素。他们被分成 find_element_* 和 find_elements_* 方法。前者返回的WebElement对象,代表页面中匹配查询的第一个元素,而后者包含所有匹配元素的列表。
在Webdriver对象上调用的方法:
方法名 | 返回的WebElement对象/列表 |
browser.find_element_by_class_name(name) browser.find_elements_by_class_name(name) |
类名为name的元素 |
browser.find_element_by_css_selector(selector) browser.find_elements_by_css_selector(selector) |
selector为css选择器,如同我们写样式时写的内容如“#head” 返回匹配的元素 |
browser.find_element_by_id(id) browser.find_elements_by_id(id) |
id名为id的元素 |
browser.find_element_by_link_text(text) browser.find_elements_by_link_text(text) |
返回a元素中文本内容完全为text的a元素 |
browser.find_element_by_partial_link_text(text) browser.find_elements_by_partial_link_text(text) |
partial:局部 返回a元素中文本内容包含text的元素 |
browser.find_element_by_name(name) browser.find_elements_by_name(name) |
匹配name属性值为name的元素 |
browser.find_element_by_tag_name(name) |
匹配标签名为name的元素 (大小写无关‘a’和'A'都会匹配便签<a>) |
注意:
除了最后一个方法,其他的参数都是区分大小写的。如果页面上没有元素被匹配,selenium模块就会抛出 NoSuchElement 异常。即要配合 try....except 语句
使用类名和id来查找元素时,注意不要有空格,因为空格前后的内容会被HTML解释成两个
当界面跳转后,如果原来的查找结果还能有匹配,那么就不用重新匹配
上述方法假如匹配成功,会返回一个 WebElement 对象,对于这个对象可以使用下面的属性或方法:
方法或者属性 | 描述 |
tag_name | 标签名,例如‘a’(这个是返回的值)代表<a>元素 |
get_attribute(name) | 该元素 name属性 的值 |
text | 该元素内的文本,例如<span>hello</span>中的‘hello’ |
clear() |
对于文本字段或文本区域元素,清除其中输入的文本 不能清除<a>里面的,估计<span>里的也不能 |
is_displayed() | 如果该元素可见,返回True,可以用于先判断元素是否可见 |
is_enabled() | 对于输入元素,如果该元素启用,返回True |
is_selected() | 对于复选框或者单选元素,如果该元素被选中,返回True |
location | 一个字典,包含键‘x’和'y',表示该元素在页面上的位置 |
示例:
from selenium import webdriver browser=webdriver.Chrome() browser.get('http://www.baidu.com') try: elem=browser.find_element_by_class_name('head_wrapper')#寻找第一个类名为head_wrapper的元素 print('找到了相应类名的元素:<%s>'%(elem.location)) except: print('没有找到这个元素。') browser.quit()
1.3点击页面
利用 WebElement 对象的click()方法,我们可以模拟鼠标在该元素上单击。效果与我们手动单击的效果一样
示例:
from selenium import webdriver browser=webdriver.Chrome() browser.get('http://www.baidu.com') try: elem=browser.find_element_by_class_name('mnav')#会匹配到“新闻” print('找到了相应类名的元素:<%s>'%(elem.location)) elem.click() except: print('没有找到这个元素。') browser.quit()
1.4输入内容send_key()
是webElement对象的方法
1.5填写并提交表单
webElement对象方法 submit() ,在任何元素上使用 submit() 方法,都相当于点击该元素所在表单的submit按钮
示例:
import logging #此行以及下两行行是使用日志内容 logging.basicConfig(level=logging.CRITICAL,format=' %(asctime)s - %(levelname)s -%(message)s') from selenium import webdriver logging.disable(logging.ERROR) browser=webdriver.Chrome() browser.get('http://www.baidu.com') try: elem=browser.find_element_by_id('kw') logging.critical('输入框已经找到') elem.send_keys('长泽雅美') #是keys logging.critical('内容已输入') searchElem=browser.find_element_by_id('su') logging.critical('按钮已经找到') searchElem.submit() logging.critical('已提交') except: print('没有找到这个元素。') browser.quit()
注意,不用在寻找提交按钮上花费太长时间,因为在任何元素上使用 submit() 方法,都等同于你点击了这个元素所属表单的提交按钮,你甚至可以这样(我不确定,你可以打开百度首页,输入内容演示一下,就能知道我的意思了你可能发现你不需要点击搜索按钮,就会出现搜索结果)
---snip---- elem.submit() #改动在这里 logging.critical('已提交') ---snip---
1.6发送特殊键
当我们需要向浏览器击键行为,如按下‘F12’,这时仅通过字符串值输入时不可能完成的,selenium为我们这种需要提供了一个解决办法:这些值保存在selenium.webdriver.common.keys模块的属性中。由于这个模块的名字非常长,我们可以通过from selenium.webdriver.common.keys import Keys,让from selenium.webdriver.common.keys.Keys.F12简写为:Keys.F12
下表展示了一些selenium.webdriver.common.keys模块中常用的变量:
属性 | 含义 |
Keys.DOWN,Keys.UP,Keys.LEFT,Keys.RIGHT | 键盘方向键 |
Keys.ENTER,Keys.RETURN | 回车键和换行键 |
Keys.HOME,Keys.END,Keys.PAGE_DOWN,Keys.PAGE_UP | |
Keys.ESCAPE,Keys.BACK_SPACE,Keys.DELETE | Esc,backspace和消除键 |
Keys.F1,Keys.F2........Keys.F12 | |
Keys.TAB |
示例:使页面向下滚动一次
import time import logging #此行以及下两行行是使用日志内容 logging.basicConfig(level=logging.CRITICAL,format=' %(asctime)s - %(levelname)s -%(message)s') from selenium import webdriver logging.disable(logging.ERROR) from selenium.webdriver.common.keys import Keys browser=webdriver.Chrome() browser.get('http://www.baidu.com') try: elem=browser.find_element_by_id('kw') logging.critical('输入框已经找到') elem.send_keys('长泽雅美') #是keys logging.critical('内容已输入') searchElem=browser.find_element_by_id('su') logging.critical('按钮已经找到') elem.submit() logging.critical('已提交') htmlElem=browser.find_element_by_tag_name('html') htmlElem.send_keys(Keys.PAGE_DOWN) except: print('没有找到这个元素。') time.sleep(3) #不加这个暂停看不出来效果 browser.quit()
注意:
(未证明)要对合适的元素对象使用相应的按键,如果上面你对'elem'使用这不会有效果
是keys要加s
问题:
使用Keys.PAGE_DOWN,时必须在前面加sleep()才能实现
import time import logging #此行以及下两行行是使用日志内容 logging.basicConfig(level=logging.CRITICAL,format=' %(asctime)s - %(levelname)s -%(message)s') from selenium import webdriver logging.disable(logging.ERROR) from selenium.webdriver.common.keys import Keys browser=webdriver.Chrome() browser.maximize_window() browser.get('http://www.baidu.com') try: elem=browser.find_element_by_id('kw') logging.critical('输入框已经找到') elem.send_keys('长泽雅美') #是keys logging.critical('内容已输入') searchElem=browser.find_element_by_id('su') logging.critical('按钮已经找到') elem.submit() logging.critical('已提交') htmlElem=browser.find_element_by_tag_name('html') logging.critical('html标签已找到') time.sleep(2) elem.send_keys(Keys.PAGE_DOWN)#必须前面使用sleep()暂停才有用 logging.critical('按键已激发') except: print('没有找到这个元素。') time.sleep(10) browser.quit()
不能发送F5按键使浏览器窗口刷新(可以使用browser.refresh()),无论是对html标签元素还是其他元素使用均无效
import time import logging #此行以及下两行行是使用日志内容 logging.basicConfig(level=logging.CRITICAL,format=' %(asctime)s - %(levelname)s -%(message)s') from selenium import webdriver logging.disable(logging.ERROR) from selenium.webdriver.common.keys import Keys browser=webdriver.Chrome() browser.maximize_window() browser.get('http://www.baidu.com') try: elem=browser.find_element_by_id('kw') logging.critical('输入框已经找到') elem.send_keys('长泽雅美') #是keys logging.critical('内容已输入') searchElem=browser.find_element_by_id('su') logging.critical('按钮已经找到') elem.submit() logging.critical('已提交') htmlElem=browser.find_element_by_tag_name('html') logging.critical('html标签已找到') time.sleep(2) elem.send_keys(Keys.F5)#必须前面使用sleep()暂停才有用 logging.critical('按键已激发') except: print('没有找到这个元素。') time.sleep(10) browser.quit()
1.6点击浏览器按钮
这里的浏览器按钮指的是浏览器应用里的按钮,
browser.back() 点击返回按钮
browser.froward() 点击前进按钮
browser.refresh() 点击刷新按钮
browser.quit() 点击关闭窗口按钮
二、selenium的更多信息
browser.maximize_windows():设置浏览器大小为全屏
browser.set_window_size(500,500):设置浏览器窗口大小为500*500
组合键操作:https://www.cnblogs.com/mengyu/p/6942584.html
更详细的信息包括 拖放:https://www.cnblogs.com/zhongyehai/p/9163740.html
说send_keys()不能输入中文的解决办法是send_keys(u' ')
三、遇到的问题:
1)selenium.common.exceptions.WebDriverException:Message: 'geckodriver' executable needs to be in PATH.
问题是有你没有浏览器驱动,或者浏览器驱动所在的文件夹没有在环境变量PATH里面
在执行以下代码时出现了上个异常
>>> from selenium import webdriver >>> browser=webdriver.Firefox() Traceback (most recent call last): File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\common\service.py", line 76, in start stdin=PIPE) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\subprocess.py", line 775, in __init__ restore_signals, start_new_session) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\subprocess.py", line 1178, in _execute_child startupinfo) FileNotFoundError: [WinError 2] 系统找不到指定的文件。 During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<pyshell#1>", line 1, in <module> browser=webdriver.Firefox() File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\firefox\webdriver.py", line 164, in __init__ self.service.start() File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\common\service.py", line 83, in start os.path.basename(self.path), self.start_error_message) selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
解决办法:(错误虽然没有别我解决,但基于相似问题有庞大的搜索结果。相信仍然有一定的借鉴意义)
错误是英文的,我先把他翻译过来之后,这个错误的意思是“geckodriver”需要在环境变量访问到才能执行。 由于是第一次使用selenium模块,我搜索了模块的使用方法,然后发现需要针对Firefox浏览器的webdriver驱动文件,然后就下载了。发现下载太慢,然后又按照另外一个方法解决办法:“出现这样的错误是浏览器没有安装到默认位置,需要修改selenium模块里的两个参数”(这个办法没有用,你只需要将浏览器的安装文件夹添加到PATH里面)
D:\Programs\Python\Python35-32\Lib\site-packages\selenium-3.0.1-py3.5.egg\selenium\webdriver\firefox的 webdriver.py文件中修改为 def_init_(self,firefox_profile=None,firefox_binary=FirefoxBinary("D:/Program Files (x86)/Mozilla Firefox/firefox.exe")#其中的是浏览器的安装位置 Firefox_binary.py文件中修改为 def_init_(self,firefox_path="D:/Program Files (x86)/Mozilla Firefox/firefox.exe",log_file=None);
然后发现还是报同样的错误,这是下载驱动文件也好了,网上说要需要配置Path变量的,我直接把它放在Python的根目录下了,因为这里已经配置过了
geckodriver的网盘链接: https://pan.baidu.com/s/1fWLiTd_1p3vn9CzBTJcfpg 提取码: uki4
GitHub链接:https://github.com/mozilla/geckodriver/releases
然后程序能运行了,能打开一个火狐浏览器窗口
>>> from selenium import webdriver >>> browser=webdriver.firefox()
我没高兴太长时间,准确来说,上述成功只运行了一次,就不行了。我试了很多办法,然后放弃了,选择了chrome
我试了下载高版本的selenium,但pip中自动安装的最新版本是3.141,我上网找了selenium的版本:版本在这里,不知道那个才是python要的,放弃
以上办法来源于参考经验:
https://www.cnblogs.com/fangfangs/p/f0000000f.html
问题 selenium.common.exceptions.SessionNotCreatedException: Message: Unable to find a matching set of capabilities
这个问题是由于你的浏览器驱动文件(geckodriver、chromedriver)版本和selenium版本不兼容导致的
>>> from selenium import webdriver
>>> browser=webdriver.firefox()
Traceback (most recent call last): File "<pyshell#2>", line 1, in <module> browser=webdriver.Firefox() File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\firefox\webdriver.py", line 174, in __init__ keep_alive=True) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 157, in __init__ self.start_session(capabilities, browser_profile) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 252, in start_session response = self.execute(Command.NEW_SESSION, parameters) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute self.error_handler.check_response(response) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response raise exception_class(message, screen, stacktrace) selenium.common.exceptions.SessionNotCreatedException: Message: Unable to find a matching set of capabilities
上网搜索发现是浏览器版本问题,决定更新浏览器版本再说,之后发现这个方法没用
首先应该让浏览器、浏览器驱动、selenium、三个的版本互相兼容:他们之间版本关系我在网上没有找到整理的好的。我就在geckodriver(针对火狐的浏览器驱动)的主页上看介绍,发现我下的v24,竟然要求Firefox是66版本的,而浏览器提示我65已经是最新,没有办法我只能继续看下去,然后找到了一个
通过查看C:\Users\Administrator.SC-2016\AppData\Local\Programs\Python\Python37\Lib\site-packages\selenium\webdriver\firefox\webdriver.xpi\install.rdf文件来查看你安装的selenium支持的浏览器版本(通过winrar查看这个文件),发现我的支持Firefox版本是3.0到52的:
然后发现Firefox版本还是太高,我下了一个51.***的。
启发:
不要想着征服错误,特别是在还有别的替代方法的情况下。
不要被搜索出来的解决办法的困难度吓到,要尽量找到高质量的解决办法,像有些错误,压根就是没按照正常流程去做而出错的。如果你找到的解决办法没有把这个讲明白,会很浪费时间