介绍

本文介绍如何获取元素以使用 Selenium 进行抓取以及如何调试。

关于本文环境 Selenium 为 4.4,浏览器使用 chrome。
如何搭建 Selenium 环境请参考之前写的让 Python 做日常工作:用 Selenium 自动化考勤处理。

检查假设

如果您的假设不正确,您将浪费时间进行调试。
如果你正在抓取并得到NoSuchElementException 异常,让我们检查一下我们的假设。

网址正确

如果您收到NoSuchElementException 异常,请确保您尝试从中获取元素的页面的 URL 是正确的。
HTTP 重定向例如,很有可能无法获得预期的响应。

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="app"]"}

Selenium 提供了current_url 方法。

参考:获取当前网址

您可以使用current_url 方法来确定URL。
以下是current_url 的结果与base_url 定义的URL 比较不正确时输出异常的示例。

try:
    if browser.current_url == f'{base_url}':
        <URLが正しい場合の処理>
    else:
        raise BatchError('failure')
finally:
    pass

如果无法解析名称,将输出以下错误消息。
如果在可以解析URI方案的主机名时输出NoSuchElementException消息,则可能是路径不正确。

selenium.common.exceptions.WebDriverException: Message: unknown error: net::ERR_NAME_NOT_RESOLVED

您尝试获取的元素名称是正确的

如果您尝试获取的元素名称错误,例如拼写错误,则会输出异常NoSuchElementException

例如,我以为我在 CSS 选择器中指定了 'app',但我不小心输入了一个太多的 p。

element = browser.find_element(By.ID, 'appp')

因为元素名称不存在,所以输出NoSuchElementException 异常。

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="appp"]"}

Selenium 提供了is_enabled() 方法。

参考:有关网络元素的信息

您可以使用is_enabled() 方法来确定元素。
如果元素有效,下面的示例将打印element: True

element = browser.find_element(By.ID, 'app').is_enabled()
print(f'element: {element}')

获取元素需要知道的事情

了解定位器位置对于通过抓取检索元素很重要。

了解定位器移动

find_elementfind_elements 被提供为用于查找元素的基本方法。
定位器的移动和方法返回值的数据类型不同,所以要了解规范并相应使用。

find_element 方法获取 DOM 中与定位器匹配的第一个元素。

element = browser.find_element(By.ID, 'wrapper')
print(f'element: {element}')
print(type(element))

上面的输出如下。

element: <selenium.webdriver.remote.webelement.WebElement (session="83637704440c02c40230f7f3c432a776", element="3962b35a-d2ae-4517-92bf-9d4d15733494")>
<class 'selenium.webdriver.remote.webelement.WebElement'>

find_elements 方法查找多个元素并将它们返回到一个列表中。

element = browser.find_elements(By.ID, 'wrapper')
print(f'element: {element}')
print(type(element))

可以看到返回的列表如下。

element: [<selenium.webdriver.remote.webelement.WebElement (session="b6272bed38cd78b07fdcba2f7fafbb4c", element="14ba230f-78b6-4e8f-bc08-ccd001d950f4")>]
<class 'list'>

参考:搜索网络元素

总之,find_element 方法只检索在搜索中找到的第一个元素。要获取多个元素,请使用find_elements 方法。

XPath 和 CSS 选择器

XML 路径语言(少于,XPath) 很有用,例如,当您要检索的元素没有合适的 ID 时。
基于 XPath 的机制,它是从根目录开始的绝对路径引用的,所以如果网站发生变化,可能无法获取。

当唯一 id 不可用时,编写良好的 CSS 选择器是查找元素的好方法。 XPath 的工作方式类似于 CSS 选择器,但语法复杂且通常难以调试。 XPath 非常灵活,但浏览器供应商通常不会对其进行性能测试,而且速度往往很慢。

参考:使用定位器的提示

桌子

硒是桌子也可以获得元素。
与BeautifulSoup一样,从包含获取到的table元素的对象中tr元素和时间提取元素。
对象以列表类型存储,因此您可以通过执行for 语句来获取tr 元素。

以下是使用app ID 缩小范围并检索表元素数据的示例。

# id
element = browser.find_element(By.ID, 'app')

# table
table = element.find_element(By.TAG_NAME, 'table')

# tr
tr_list = table.find_elements(By.TAG_NAME, 'tr')

从作为一组检索行的tr_list 对象中,指定作为单元格数据的td_list 的索引,然后提取它。
如果表格有两个单元格数据,请按如下方式指定索引。

table_list = []

for index, row in enumerate(tr_list):
    # ヘッダはスキップ
    if index == 0:
        continue

    # td
    td_list = row.find_elements(By.TAG_NAME, 'td')

    td_dict = {'name': td_list[0].text,
               'price': td_list[1].text} 
    table_list.append(td_dict)                             

纽扣

根据网站的结构,通过爬取连续获取数据的难易程度不同。
对于通过如下所示在请求标头中指定查询参数来执行 HTTP 通信的站点,我认为这很容易,因为它只会增加 page= 的值。

https://<WebサイトのURL>/list/?page=2

由SPA等组成的网站。纽扣对于内容根据客户端移动(例如元素)而以不同方式加载和显示的站点,需要加载内容的说明。

因此,在由如下所示的按钮元素组成的内容的情况下,除非单击表示页码的数字,否则无法显示下一个数据。

SeleniumでスクレイピングをするためのTips

作为一种解决方案,您可以使用上面介绍的is_enabled() 方法来创建逻辑,例如如果按钮存在则加载下一个内容,如果不存在则退出页面。

在下面的示例中,由 table 元素组成的内容的 CSS 选择器第n个孩子递增以确定接下来要加载的按钮。
如果button.is_enabled() 结果为True,单击按钮加载下一个内容。

flag = True
num = 2

while flag is True:
    # id
    element = browser.find_element(By.ID, 'app')
    # table
    table = element.find_element(By.TAG_NAME, 'table')
    # tr
    tr_list = table.find_elements(By.TAG_NAME, 'tr')
  
    try:
        if flag is True:
            num += 1
            button = element.find_element(By.CSS_SELECTOR, "CSSセレクタのパス > li:nth-child("+(str(num))+") > button")
            if button.is_enabled() is True:
                button.click()
            else:
                flag = False
    except common.exceptions.NoSuchElementException as e:
       continue

框架和 iframe

在 HTML5 中,框架元素和框架集元素已弃用。

我想你可能会在遗留系统等中看到它。内嵌框架同样,您可以通过指定和访问实体来进行抓取。

参考:使用 iFrame 和框架

其他

如何使用个人资料

默认情况下,ChromeDriver 会为每个会话创建一个新的临时配置文件。
如果想接管session等登录信息,可以通过Chrome的用户配置文件来解决。

下面是使用 Chrome 的用户配置文件作为驱动程序选项的示例。
profile_path 可以通过打开 Chrome 并访问 chrome://version/ 找到。

from selenium import webdriver

options = webdriver.chrome.options.Options()
profile_path = '/Users/<Your Name>/Library/Application Support/Google/Chrome/Default'
options.add_argument('--user-data-dir=' + profile_path)

参考:选项

有关驱动程序选项的更多信息,请参阅 ChromeDriver 的常见用例你可以检查更多。

尝试/除

如果你因为找不到元素而得到NoSuchElementException 异常,并且想要继续而不停止,你可以使用common.exceptions.NoSuchElementException 来捕获异常。

from selenium import common

try:
    <何らかの処理>
except common.exceptions.NoSuchElementException as e:
    continue

睡眠处理

即使元素存在,在渲染耗时较长时可能会出现NoSuchElementException,可能无法获取到元素。

作为对策,您可以使用标准模块的time.sleep 函数轻松实现睡眠处理,但是 Selenium 有显式等待什么时候,隐式等待有两种方法称为

参考:支持

僵尸进程

在运行 Selenium 时未能正确终止 quit() 会使驱动程序的僵尸进程在后台运行。
如果服务器使用 cron 等定期运行它,内存不会被释放,造成不必要的内存消耗。

hoge     68212   0.0  0.0 37946300   6680 s002  S     4:16PM   0:05.48 /Users/hoge/.wdm/drivers/chromedriver/mac64/106.0.5249/chromedriver --port=61942
hoge     67990   0.0  0.0 37946300   6668 s002  S     4:04PM   0:02.43 /Users/hoge/.wdm/drivers/chromedriver/mac64/106.0.5249/chromedriver --port=58852
hoge     67539   0.0  0.0 37957564   6684 s002  S     3:32PM   0:01.95 /Users/hoge/.wdm/drivers/chromedriver/mac64/106.0.5249/chromedriver --port=50768
hoge     66708   0.0  0.0 37946300   6660 s002  S     2:48PM   0:00.45 /Users/hoge/.wdm/drivers/chromedriver/mac64/106.0.5249/chromedriver --port=55595

下面是一个可以使用shell的环境下单行处理的例子,比如Mac或者Linux。

ps=`ps aux | grep 'chromedriver' | grep -v grep | awk '{print  $2 }'`;for i in $ps; do kill $i; done

参考:在会话结束时退出浏览器

让我们以 quit() 结束 Selenium。

综上所述

采集时知法。

过去,欺诈性妨碍业务的案件,或网站负载过大的案件,可能会触及刑法“第234条”(损害计算机等妨碍业务)。

此外,如果获取的数据的处理出现问题,则可能会触及版权法。


原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308631907.html

相关文章: