20220630 selenium学习
0、
最新版的谷歌浏览器驱动放在win10系统中的C:\Program Files\Google\Chrome\Application目录下。
1、
今天在学习selenium中Xpath用法。网上介绍xpath是一种在xml文件中定位的方法,html文件可以看作是xml(xhtml),因此也可以用xpath来定位。这也是我最推荐的一种方式,xpath定位的方法一般都是特征字定位后再利用路径来定位元素,相对来说最为灵活,也最为精准。例子如下
login_form = driver.find_element_by_xpath("/html/body/form[1]") login_form = driver.find_element_by_xpath("//form[1]") login_form = driver.find_element_by_xpath("//form[@id='loginForm']") username = driver.find_element_by_xpath("//form[input/@name='username']") username = driver.find_element_by_xpath("//form[@id='loginForm']/input[1]") username = driver.find_element_by_xpath("//input[@name='username']")
(1)发现了一个小技巧,在chrome浏览器中的检查功能可以直接复制xpath。直接在F12打开工作台可以定位到相关标签并copy即有xpath选项,真是方便呢。
关于selenium抓取相关报错的问题,可以参考该大佬的文章:https://www.cnblogs.com/liwxmyself/p/15330909.html。
比如说下面这一列复制出的内容,其中有div[1]和div[2]不同层级的元素,这种就是谓语表达式了。谓语用来查找某个特定的节点或者包含某个指定值的节点,被嵌在方括号中。(参考链接:https://blog.csdn.net/weixin_39549852/article/details/113326118)
复制出来的xpath路径,可以在控制台用ctrl+f搜索对应元素,匹配结果会标记黄色,可以验证是否正确。
browser.find_element_by_xpath("//*[@id='pane-callCenter']/div[1]/form/div[2]/div/div/div/input")
(2)selenium如何用xpath中如何定位下拉框里选项?实际上select工具就是selenium提供的选择工具。
from selenium.webdriver.support.select import Select
其中有三种定位选项的方法:
- select_by_index():索引定位(从0开始)
- select_by_value():value属性定位
- select_by_visible_text():选项的文本属性
举例,用选择器定位文本属性选择(参考链接:https://www.cnblogs.com/haifeima/p/10209635.html)。
coding = utf-8 from selenium import webdriver from selenium.webdriver.support.select import Select from selenium.webdriver.common.action_chains import ActionChains from time import sleep # 驱动文件路径 driverfile_path = r'D:\coship\Test_Framework\drivers\chromedriver.exe' # 启动浏览器 driver = webdriver.Chrome(executable_path=driverfile_path) # 打开百度首页 driver.implicitly_wait(10) driver.get(r'https://www.baidu.com/') # 移动鼠标到设置上,再点击搜索设置 set = driver.find_element_by_link_text("设置") ActionChains(driver).move_to_element(set).perform() driver.find_element_by_link_text("搜索设置").click() # 通过text定位 sel = driver.find_element_by_css_selector("select#nr") Select(sel).select_by_visible_text("每页显示20条") # 退出 sleep(5) driver.quit()
用文本属性选择方式能顺利定位到选项。
3、
晚上继续尝试selenium多页数据查询提取。
多界面数据提取有多种办法,关于翻页的处理,可以有如下几种常用方法:
(1)用while持续翻页至末页;(2)输入页码确定进行翻页;(3)先获取最大页码,然后用for page in range(max_page)进行翻页。(参考链接:https://zhuanlan.zhihu.com/p/331717198)
先记录方法(2)的示例代码:
import re from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from pyquery import PyQuery as pq ''' wait.until()语句是selenum里面的显示等待,wait是一个WebDriverWait对象,它设置了等待时间,如果页面在等待时间内 没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常,也可以说程序每隔xx秒看一眼,如果条件 成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException 1.presence_of_element_located 元素加载出,传入定位元组,如(By.ID, 'p') 2.element_to_be_clickable 元素可点击 3.text_to_be_present_in_element 某个元素文本包含某文字 ''' # 定义一个无界面的浏览器 browser = webdriver.PhantomJS( service_args=[ '--load-images=false', '--disk-cache=true']) # 10s无响应就down掉 wait = WebDriverWait(browser, 10) #虽然无界面但是必须要定义窗口 browser.set_window_size(1400, 900) def search(): ''' 此函数的作用为完成首页点击搜索的功能,替换标签可用于其他网页使用 :return: ''' print('正在搜索') try: #访问页面 browser.get('https://www.taobao.com') # 选择到淘宝首页的输入框 input = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, '#q')) ) #搜索的那个按钮 submit = wait.until(EC.element_to_be_clickable( (By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button'))) #send_key作为写到input的内容 input.send_keys('面条') #执行点击搜索的操作 submit.click() #查看到当前的页码一共是多少页 total = wait.until(EC.presence_of_element_located( (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.total'))) #获取所有的商品 get_products() #返回总页数 return total.text except TimeoutException: return search() def next_page(page_number): ''' 翻页函数, :param page_number: :return: ''' print('正在翻页', page_number) try: #这个是我们跳转页的输入框 input = wait.until(EC.presence_of_element_located( (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input'))) #跳转时的确定按钮 submit = wait.until( EC.element_to_be_clickable( (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.J_Submit'))) #清除里面的数字 input.clear() #重新输入数字 input.send_keys(page_number) #选择并点击 submit.click() #判断当前页是不是我们要现实的页 wait.until( EC.text_to_be_present_in_element( (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number))) #调用函数获取商品信息 get_products() #捕捉超时,重新进入翻页的函数 except TimeoutException: next_page(page_number) def get_products(): ''' 搜到页面信息在此函数在爬取我们需要的信息 :return: ''' #每一个商品标签,这里是加载出来以后才会拿网页源代码 wait.until(EC.presence_of_element_located( (By.CSS_SELECTOR, '#mainsrp-itemlist .items .item'))) #这里拿到的是整个网页源代码 html = browser.page_source #pq解析网页源代码 doc = pq(html) items = doc('#mainsrp-itemlist .items .item').items() for item in items: # print(item) product = { 'image': item.find('.pic .img').attr('src'), 'price': item.find('.price').text(), 'deal': item.find('.deal-cnt').text()[:-3], 'title': item.find('.title').text(), 'shop': item.find('.shop').text(), 'location': item.find('.location').text() } print(product) def main(): try: #第一步搜索 total = search() #int类型刚才找到的总页数标签,作为跳出循环的条件 total = int(re.compile('(\d+)').search(total).group(1)) #只要后面还有就继续爬,继续翻页 for i in range(2, total + 1): next_page(i) except Exception: print('出错啦') finally: #关闭浏览器 browser.close() if __name__ == '__main__': main()
方法(3)的示例:
# coding=utf-8 import os import time from selenium import webdriver #打开火狐浏览器 需要V47版本以上的 driver = webdriver.Firefox()#打开火狐浏览器 url = "http://codelife.ecit-it.com"#这里打开我的博客网站 driver.get(url)#设置火狐浏览器打开的网址 time.sleep(2) #使用xpath进行多路径或多元素定位,用法看官网http://selenium-python.readthedocs.io/locating-elements.html elem_dh = driver.find_elements_by_xpath("//div[@class='pagination pagination-large']/ul/li/a") print ("我是刚获取的翻页按钮的路径数组:",elem_dh) print ("下一页按钮元素:",elem_dh[2]) time.sleep(5) #获取当前窗口句柄 now_handle = driver.current_window_handle #获取当前窗口句柄 print ("我是当前窗口的句柄:",now_handle)#打印窗口句柄 是一串数字 time.sleep(10) #循环获取界面 for elem in elem_dh: print ("我是翻页按钮上的文本信息:",elem.text) #获取元素的文本值 print ("我是翻页按钮的地址",elem.get_attribute('href')) #获取元素的href属性值 elem.click()#点击进入新的界面 _blank弹出 print ("刚翻页完成了!") time.sleep(20)
我倾向于用方法(2)获取界面信息,尝试吧。
4、
selenium加载出的页面,如何提取数据呢?用selenium
把网页打开,所有信息就都加载到了Elements
那里,之后,就可以把动态网页用静态网页的方法爬取了。(参考链接:https://www.cnblogs.com/ywb123/p/16414374.html)
举例来说,提取网页元素的方法:
# 以下方法都可以从网页中提取出'你好,蜘蛛侠!'这段文字 find_element_by_tag_name:通过元素的名称选择 # 如<h1>你好,蜘蛛侠!</h1> # 可以使用find_element_by_tag_name('h1') find_element_by_class_name:通过元素的class属性选择 # 如<h1 class="title">你好,蜘蛛侠!</h1> # 可以使用find_element_by_class_name('title') find_element_by_id:通过元素的id选择 # 如<h1 id="title">你好,蜘蛛侠!</h1> # 可以使用find_element_by_id('title') find_element_by_name:通过元素的name属性选择 # 如<h1 name="hello">你好,蜘蛛侠!</h1> # 可以使用find_element_by_name('hello') #以下两个方法可以提取出超链接 find_element_by_link_text:通过链接文本获取超链接 # 如<a href="spidermen.html">你好,蜘蛛侠!</a> # 可以使用find_element_by_link_text('你好,蜘蛛侠!') find_element_by_partial_link_text:通过链接的部分文本获取超链接 # 如<a href="https://localprod.pandateacher.com/python-manuscript/hello-spiderman/">你好,蜘蛛侠!</a> # 可以使用find_element_by_partial_link_text('你好')
测试提取数据的类型
# 本地Chrome浏览器设置方法 from selenium import webdriver #从selenium库中调用webdriver模块 driver = webdriver.Chrome() # 设置引擎为Chrome,真实地打开一个Chrome浏览器 import time driver.get('https://localprod.pandateacher.com/python-manuscript/hello-spiderman/') # 访问页面 time.sleep(2) # 等待2秒 label = driver.find_element_by_tag_name('label') # 解析网页并提取第一个<lable>标签中的文字 print(type(label)) # 打印label的数据类型 print(label.text) # 打印label的文本 print(label) # 打印label driver.close() # 关闭浏览器
今天先学到这里,明天继续。
5、
220701
今天试着用显式等待设置获取元素,但是用如下代码报错,
wait.until(EC.presence_of_element_located((By.XPATH, "//*[@id='main-frame']/div[2]/div[3]/div[2]/div[2]/div[6]/div/div[1]/div/div[1]/button/i")))
在网上查了下相关问题解决思路,presence_of_element_located
类中__init__()
方法取的确实是2个参数(self, locator),其中locator调用的是一个tuple(元组),该元组(By.ID,"su")
作为一个整体,对应相当于1个参数,加上类实例化代表自身的self参数,正好就是2个参数。因此,执行代码正确的写法为:presence_of_element_located((By.ID,"su"))
,即需要嵌套两层英文圆括号。尝试了下,问题解决。(参考链接:https://www.jianshu.com/p/f22bd90756bf)
还想用无头浏览器模式爬取数据,发现怎么也抓不到数据,尝试了一个小时多,各种找资料,最终在知乎上找到了解决方法(参考链接:https://www.zhihu.com/question/390628859)。按照其中回答,我判断爬取的网站,应该是将附加的Headless
参数/属性作为bot被拦截,将option添加几种属性后,成功实现无头浏览模式。代码如下:
options = webdriver.ChromeOptions() options.add_argument('headless') options.add_argument('--window-size=1920,1080') options.add_argument("user-agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'") browser = webdriver.Chrome(options=options) #browser = webdriver.Chrome() wait = WebDriverWait(browser, 10)
6、
用selenuim获取到页面后,可用pyquery定位爬取元素(参考链接:https://www.cnblogs.com/cttcarrotsgarden/p/10770430.html)。
不过如果单纯用selenium实现爬取数据又如何操作呢?可以试着将数据放到字典中,循环取数据。(参考链接:https://cloud.tencent.com/developer/article/1727204)
尝试了下,放到字典里并不好用,干脆用列表操作,循环爬取数据。为什么这么说?因为用find_elements_by_xpath提取出来的列表中,dict类型的,key、value抓出的元素不知道如何进一步处理了,value的值提取出来是
{'user-id': <selenium.webdriver.remote.webelement.WebElement (session="c49e639f55923ff9eeeee4d4bf312695", element="52bb299a-83bd-4968-a1f2-87509e73fdb3")>}
不知道如何继续用了。只能转换思路用列表形式,查了下webelement元素的相关操作,用如下方法可行(参考链接:https://blog.csdn.net/weixin_54767527/article/details/121451467):
import time from selenium import webdriver driver = webdriver.Chrome() driver.get('http://tendcode.com/accounts/login/?next=/') driver.maximize_window() # 网页最大化 driver.find_element_by_id('id_login').send_keys('asdfghjkl') # 输入用户名 driver.find_element_by_id('id_password').send_keys('123.123.') # 输入密码 driver.find_element_by_class_name('pull-right').click() # 点击登录 ds = [] for i in range(1,5): # 循环 div_a= driver.find_element_by_xpath('/html/body/main/div/div/div[1]/div[3]/div[%s]/div[2]/h2'%i) # 循环查找这五个元素 ss = div_a.find_element_by_tag_name('a') # 获取div_a下的a标签 ds.append(ss.text) # 添加到列表 print(ss.text) # 输出文本 print(ss) # 输出元素信息 print(ds) time.sleep(5) driver.quit()
试了下,将思路移植到目标网站上,的确可实现元素抓取。但此获取到的网页元素为单个列表,后续需要用pandas等工具进行数据转换才好保存处理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?