前言
通过爬虫直接抓取网页HTML源码里面的数据可能并没有我们想要的数据,这是因为网页通过JavaScript动态渲染过了。除了Ajax技术外,有些网页不通过Ajax而是通过JavaScript来直接渲染页面。就算是能通过Ajax抓取,有一些比如淘宝网的Ajax接口里面拥有加密技术,很难找出其中的规律所以很难通过Ajax进行抓取。
一、引入
Python里面提供了许多模拟浏览器运行的库,在这里主要举例较为常见的Selenium,通过这个库就不用为动态渲染的网页发愁了。
二、Selenium的基本使用
2.1、准备
在使用Selenium操作谷歌浏览器之前必须下载谷歌驱动才能使用,需要下载对应或者相近版本的谷歌浏览器驱动。除了点击右上角三个点里面去查看版本号,再就是通过搜索:chrome://version/查看版本号。
下载谷歌浏览器驱动程序∶https://chromedriver.storage.googleapis.com/index.html
国内下载谷歌地址可能比较慢,我们可以通过阿里的镜像站下载,地址:https://registry.npmmirror.com/binary.html?path=chromedriver/
如果安装谷歌浏览器其驱动时,找不到匹配浏览器最新版本的驱动,如我的浏览器为最新版本的,进入:https://googlechromelabs.github.io/chrome-for-testing/
备注:下载的驱动放在和编写代码的同级目录下,放在其他路径则需要指定路径地址。
2.2、声明浏览器对象
| from selenium import webdriver |
| |
| |
| browser = webdriver.Chrome() |
| browser = webdirver.Firefox() |
| browser = webdirver.Edge() |
| browser = webdirver.PhantomJS() |
| browser = webdriver.Safari() |
| |
| |
| from selenium import webdriver |
| from selenium.webdriver.common.keys import Keys |
| from selenium.webdriver.common.by import By |
| from selenium.webdriver.chrome.service import Service |
| |
| |
| browser = webdriver.Chrome(service=Service(r'D:\software\PyCharmLib\chromedriver.exe')) |
| |
| |
| |
| browser.get('http://www.baidu.com') |
| |
| search = browser.find_element(by=By.ID, value='kw') |
| |
| |
| search.send_keys('python') |
| search.send_keys(Keys.ENTER) |
| |
| |
| browser.close() |
| |
| option = webdriver.ChromeOptions() |
| option.add_experimental_option("detach", True) |
| |
| webdriver = webdriver.Chrome(options=option) |
2.3、访问页面
简单的示例来进行selenium运用。
| from selenium import webdriver |
| from selenium.webdriver.common.by import By |
| |
| browser = webdriver.Chrome() |
| browser.get('https://www.taobao.com') |
| input_third = browser.find_element(by=By.XPATH, value='//*[@id="q"]') |
| print(input_third) |
| browser.close() |
2.4、设置浏览器大小、刷新、后退前进页面
| |
| browser.set_window_size(500, 500) |
| |
| |
| browser.maximize_window() |
| |
| |
| browser.refresh() |
| |
| |
| browser.forward() |
| browser.back() |
| |
| time.sleep(random.uniform(intx,inty)) |
2.5、获取页面基础属性
| |
| title = browser.title |
| |
| url = browser.current_url |
| |
| name = browser.name |
| |
| source = browser.page_source |
三、Selenium定位元素
节点交互:输入文字时使用send_key( )方法,清空文字使用clear( )方法,点击按钮时使用click( )方法。
3.1 ID定位
| |
| from selenium.webdriver.common.by import By |
| |
| browser.find_element(By.ID, 'toolbar-search-input').send_keys('Python') |
3.2 NAME定位
| |
| browser.find_element(By.NAME, 'wd').send_keys('Python') |
3.3 CLASS定位
| |
| browser.find_element(By.CLASS_NAME, 's_ipt').send_keys('Python') |
3.4 tag定位 (标签匹配)
| |
| h = browser.find_element(By.TAG_NAME, 'h3').text |
3.5 link定位(a标签内文本)
| |
| browser.find_element(By.LINK_TEXT, '新闻').click() |
3.6 partial定位(模糊匹配文本)
| |
| |
| browser.find_element(By.PARTIAL_LINK_TEXT, '课程').click() |
3.7 Xpath定位
| |
| browser.find_element(By.XPATH, "//*[@id='toolbar-search-input']").send_keys('Python') |
3.8 CSS定位(css选择器)
| |
| browser.find_element(By.CSS_SELECTOR, "#toolbar-search-input").send_keys('Python') |
3.9 文本定位(和link不一样)
能不能直接通过文本内容去定位元素,但是这个元素又不是超链接a,此时可以通过下面的方法来定位元素。注意的是也是优先捕捉第一个检测到的元素,属于模糊搜索
| |
| browser.find_element(By.XPATH, "//*[contains(text(), '你想要定位的文本内容')]") |
3.10 多元素
| |
| find_selement(By.ID, 'id').click() |
| find_selements(By.ID, 'id') |
四、Selenium获取元素属性
通过第3点的定位方式,我们已经基本掌握了全部定位方式。那么我就可以通过定位来获取定位元素的属性了,在通过Selenium数据收集/网络爬虫的时候,能让我们更方便进行数据采集。
4.1 获取属性- get_attribute()
| from selenium import webdriver |
| |
| |
| logo = browser.find_element(By.XPATH, "//div[@class='toolbar-subMenu-box']//img") |
| |
| logo.get_attribute('title') |
| logo.get_attribute('src') |
4.2 获取文本
| |
| txt = browser.find_element(By.XPATH, "//dd[@class='desc']//a").text |
4.3 获取其他属性 - id、location、size、tag_name
除了获取文本之外,我们还需要关注几个常用属性。例如id、locaition位置、size大小(图片)、tag_name标签名等。
| |
| hot_img = browser.find_element(By.XPATH, "//dt[@data-v-e8da5228]/a/img") |
| print(hot_img.text) |
| print(hot_img.id) |
| print(hot_img.location) |
| print(hot_img.tag_name) |
| print(hot_img.size) |
五、Selenium交互效果
5.1 回车确认 - submit()
| inputs = browser.find_element(By.ID, 'kw').send_keys('Python') |
| time.sleep(1) |
| |
| inputs.submit() |
5.2 单选、多选
有时候网页上的元素需要鼠标悬停出现元素才能点击。再selenium中没有专门的这种方法函数,所以思路是直接源码定位到这个悬停出现的单选元素。然后click()点击一下就可以。
| from selenium.webdriver.common.action_chains import ActionChains |
| |
| div_element = browser.find_element(By.ID, 's-usersetting-top') |
| ActionChains(browser).move_to_element(div_element).perform() |
| time.sleep(1) |
| |
5.3 下拉框 -Select
- 定位选择框的方法:
- select_by_index() # 通过索引定位,index从0开始算
- select_by_visible_text() # 通过文本值定位,即下拉框的值
- 取消已选中项的方法:
- deselect_all() # 取消已选中的所有项
- deselect_by_index() # 取消已选中的等于index索引的项
- deselect_by_visible_text() # 取消已选中的等于文本值的项
| from selenium.webdriver.support.select import Select |
| |
| sel = Select(browser.find_element(By.NAME, 'fruit')) |
| |
| |
| sel.select_by_index(1) |
| print('第一个选中项:%s'%(sel.first_selected_option.text)) |
| |
| |
| sel.select_by_visible_text('西瓜') |
| time.sleep(2) |
5.4 处理弹窗
有时候使用selenium操作网页的时候会遇见alert提示弹窗、confirm取消和确定弹窗、输入内容的prompt弹窗。核心方法有:
| text() |
| accept() |
| dismiss() |
| send_keys() |
| |
| |
| browser.find_element(By.ID, 'alert').click() |
| |
| alert = browser.switch_to.alert |
| alert.accept() |
| |
| |
| |
| browser.find_element(By.ID, 'confirm').click() |
| |
| confirm = browser.switch_to.alert |
| |
| confirm.accept() |
| |
| |
| |
| browser.find_element(By.ID, 'prompt').click() |
| |
| prompt = browser.switch_to.alert |
| |
| prompt.send_keys('记得点个赞!!!') |
| prompt.accept() |
六、浏览器窗口和ifrme的切换
在使用selenium爬虫的过程中会遇见嵌入页面iframe网页标签。还有不断地点击进入其他网页会产生很多网页窗口。这个时候我们需要切换网页窗口进行操作,所以下面示例进入不同网页中的操作。
6.1 父子页面切换—iframe网页标签
| switch_to.frame() |
| switch_to.parent_frame() |
| |
| driver.switch_to_frame('id或name值') |
| |
| |
| elementi = driver.switch_to.frame('frame_content') |
| |
| driver.switch_to_frame(elementi) |
| ''' |
| 可以通过switch_to.parent_content(后退到父节点)方法跳出当前iframe,或者还可以通过switch_to.default_content(跳出)方法跳回最外层的页面 |
| ''' |
6.2 浏览器选项卡窗口切换
- 关闭标签页:browser.close()
- 切换标签页:browser.switch_to.window()
- 显示全部标签页:browser.window_handles(返回当前浏览器的所有窗口的句柄)
| |
| windows = driver.window_handles |
| |
| driver.switch_to.window(windows[-1]) |
| driver.close() |
七、模拟鼠标操作
上面的所有操作都是讲的如何模拟浏览器去操作,我们有时候也需要用到selenium去模拟键盘和鼠标,主要是通过ActionChains模块即可实现鼠标的基本操作。
| |
| from selenium.webdriver.common.action_chains import ActionChains |
| |
| |
| |
| |
| ActionChains(browser).context_click('选中的元素').perform() |
| |
| |
| ActionChains(browser).double_click('选中的元素').perform() |
| |
| |
| ActionChains(browser).move_to_element('选中的元素').perform() |
| |
| |
| ActionChains(browser).drag_and_drop('选中的元素').perform() |
| |
| |
| ActionChains(driver).move_by_offset(x, y).click().perform() |
| |
| action.reset_actions() |
八、模拟键盘操作
模拟鼠标使用的是ActionChains,当然还有模拟键盘的操作,模拟键盘使用的是Keys模块,通过send_keys()、key_down()、key_up() 等方法来搭配使用。
Keys.BACK_SPACE |
Keys.SPACE |
Keys.TAB |
Keys.ESCAPE |
Keys.ENTER |
删除键 |
空格 |
制表键 |
回退键 |
回车键 |
Keys.ALT |
Keys.CONTROL |
Keys.SHIFT |
Keys.F1...Keys.F12 |
alt键 |
ctrl键 |
shift键 |
f1到f12键 |
| ''' |
| from selenium.webdriver.common.keys import Keys |
| 常用的组合按键 |
| send_keys(Keys.CONTROL, 'a') # 全选,ctrl+a |
| send_keys(Keys.CONTROL, 'x') # 裁剪,ctrl+x |
| send_keys(Keys.CONTROL, 'c') # 复制,ctrl+c |
| send_keys(Keys.CONTROL, 'v') # 粘贴,ctrl+v |
| ''' |
| ''' |
| 上面的使用不行的话,直接使用下面的方法(完全模拟真实操作) |
| ActionChains(driver).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform() |
| ''' |
九、加载等待
通过selenium来爬取网页的时候,由于网速以及网站服务器的带宽导致网页全部加载完成的速度有所差别。有时候通过selenium定位一个元素会因为加载时间太快导致定位不到元素,所以需要使用到selenium中的两个等待方式,分别为“隐式等待”和“显式等待”。
9.1 隐式等待
即当查找节点时并没有立即出现的时候,隐式等待讲等待一段时间再查找节点,默认时间为0。关键字:没出现,按照设置的时间等待完成后再查找。
| driver.implicitly_wait(5) |
9.2 显式等待(推荐)
隐式等待的效果其实并没有那么好,因为没有立刻找到元素,程序会根据设置的时间到了在查找一遍。而显式等待它指定一个最长等待时间,在这个时间内只要找到了元素就返回查找的节点,到了规定时间没找到,则抛出超时异常。
| from selenium.webdriver.support.ui import WebDriverWait |
| |
| |
| WebDriverWait(driver, 10).until(lambda _: driver.find_element( |
| by=By.ID, value='kw').send_keys('selenium') |
| |
| |
| webwait = WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None) |
| ''' |
| driver:浏览器驱动 |
| timeout:超时时间,秒 |
| poll_frequency:检测频率,默认是0.5秒一次 |
| ignored_exceptions:超时后的报错信息,默认是NoSuchElementException异常 |
| ''' |
| |
| webwait.until(method,msg='') |
| ''' |
| method:在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False |
| msg:如果超时,抛出TimeoutException,将msg传入异常 |
| ''' |
十、补充
10.1 Javascript调用
| |
| driver.execute_script('window.scrollTo(0, document.body.scrollHeight)') |
| |
| driver.execute_script('alert("到底了。")') |
| |
| driver.execute_script("arguments[0].setAttribute(arguments[1],arguments[2])", '元素', '属性名', '属性值') |
10.2 Cookie调用
| |
| browser.add_cookie(cookie_dict=) |
| |
| browser.get_cookie(name=) |
| |
| browser.get_cookies() |
| |
| browser.delete_cookie(name=) |
| |
| browser.delete_all_cookies() |
10.3 反屏蔽
| 一般来讲,使用selenium访问某个网址(浏览器以Chrome为例),都会有`Chrome正受到自动测试软件的控制`的提示。检测当前浏览器窗口下的window.navigator对象是否包含webdriver这个属性。因为在正常使用浏览器的情况下,这个属性是undefined的,然而,一旦我们使用了selenium,selenium会给Window.navigator设置webdriver属性,很多网站就通过JavaScript判断,如果webdriver存在就直接屏蔽。 |
Ps:方法这里就不罗列了,遇到这种情况首先通过自己手动打开浏览器可以进入网站,而通过selenium进不去,知道原因就行,遇到了在网上查找对应方法设置一下就行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~