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等工具进行数据转换才好保存处理。

posted @   dion至君  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示