前言:本文主要是基于我自己做的一个小项目:采用selenium和beautifulsoup获取163邮箱所有未读邮件内容,结合自己接触使用selenium和beautifulsoup的过程中,我将自己认为几个比较重要的地方记录下来,希望对大家有帮助。
目录
1、beautifulsoup的findall与driver.find_element(by,value)
beautifulsoup的findall可以结合正则表达式而driver.find_element(by,value)不可以结合正则表达式。
下面是使用 BeautifulSoup 结合正则表达式进行搜索的示例:
from bs4 import BeautifulSoup
import re
html = '''
<html>
<body>
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
<div class="item">Item 4</div>
<div class="item">Item 5</div>
</body>
</html>
'''
soup = BeautifulSoup(html, 'html.parser')
pattern = re.compile(r'Item \d+')
items = soup.find_all(text=pattern)
for item in items:
print(item)
在上述示例中,我们首先创建了一个包含一些 div 元素的 HTML 字符串。然后,使用 BeautifulSoup 将其解析为文档对象 soup
。
接下来,我们使用 re.compile()
函数创建了一个正则表达式模式 r'Item \d+'
,用于匹配以 "Item " 开头,后面跟着一个或多个数字的字符串。
使用 soup.find_all()
方法,并将 text
参数设置为正则表达式模式,我们可以搜索包含文本内容匹配该模式的所有元素。
最后,我们迭代输出匹配到的结果。
请注意,soup.find_all()
方法不仅可以搜索文本内容,还可以根据元素的标签名、属性等进行搜索。您可以根据实际需求调整代码。
除此之外,它们都可以查找多个满足条件的标签
查找第一个<a>标签元素
ink = soup.find('a')
查找所有<a>标签元素
links = soup.find_all('a')
查找id为div_tag[‘id’]的第一个元素
driver.find_element(By.ID, div_tag['id'])
查找id为div_tag[‘id’]的所有元素
driver.find_elements(By.ID, div_tag['id'])
2、提取标签内的元素属性
beautifulsoup提取标签内的信息:
#提取tag_a标签内的href信息
tag_a['href']
#提取tag_a标签的内容
tag_a.text
selenium方法要获取元素的 href 属性值,可以使用以下代码:
element = driver.find_element(By.ID, "my-link-id")
href_value = element.get_attribute("href")
另外,如果你想获取元素的文本内容,可以使用 text 属性:
text_content = element.text
element.get_attribute("href")
和 tag_a['href']
和tag_a.get('href', None)
element.get_attribute("href")
是selenium中的方法tag_a['href']
和tag_a.get('href', None)
是beautifulsoup的方法。
-
如果在使用
element.get_attribute("href")
方法时,href
属性不存在,那么get_attribute()
方法将返回None
。None
是在 Python 中表示空值或缺失值的特殊对象。当get_attribute()
方法无法找到指定的属性时,它会返回None
,这是一种表示属性不存在的方式。 -
如果使用
tag_a['href']
获取href
属性的值,而该属性不存在,那么会触发KeyError
错误。当使用类似于
tag['attribute']
的语法来访问元素的属性时,BeautifulSoup 会尝试返回相应属性的值。但是,如果该属性不存在,它将引发KeyError
,并且您将无法获取属性值。 -
为了避免出现
KeyError
错误,请在访问属性之前先进行检查,以确保属性存在。您可以使用.get()
方法来安全地访问属性,它不会引发错误并且可以指定默认值,以便在属性不存在时返回。以下是一个示例,演示了如何安全地获取
href
属性的值:from bs4 import BeautifulSoup html = ''' <html> <body> <a href="https://example.com">Link</a> <div>Some text</div> </body> </html> ''' soup = BeautifulSoup(html, 'html.parser') link = soup.find('a') div = soup.find('div') link_href = link.get('href', None) div_href = div.get('href', None) print(link_href) # 输出:https://example.com print(div_href) # 输出:None
在上述示例中,我们首先创建了一个简单的 HTML 文档。然后使用 BeautifulSoup 解析该文档并获取 a
元素和 div
元素。接下来,我们使用 .get('href', None)
方法分别获取了 a
元素和 div
元素的 href
属性值。如果属性不存在,默认值为 None
。对于 a
元素,它具有 href
属性,因此返回属性值 “https://example.com”。对于 div
元素,它没有 href
属性,所以返回默认值 None
。通过使用 .get()
方法,我们可以安全地获取属性的值,默认情况下返回 None
或指定的默认值,而不会引发错误。
3、元素不可交互报错 :element not interactable
出现 “selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable” 异常通常意味着目标元素无法与用户进行交互。这可能是由于以下原因之一导致的:
-
元素被其他元素所覆盖:目标元素可能位于页面上另一个元素的上方,导致无法与其进行交互。您可以尝试使用
driver.execute_script()
方法使用 JavaScript 将页面元素滚动到可见区域,然后再进行点击操作。例如:
element = driver.find_element(By.XPATH, xp) driver.execute_script("arguments[0].scrollIntoView();", element) element.click()
当调用
scrollIntoView(alignToTop)
方法时,如果不提供alignToTop
参数,则默认为true
,即元素滚动到可视区域顶部位置。 -
元素处于不可交互状态:有些元素可能因为它们的属性或当前页面状态而处于不可交互的状态,例如被禁用(disabled)或隐藏(hidden)。在执行点击操作之前,您可以检查元素的可见性、启用状态以及其他相关属性,并确保元素处于可交互的状态。
-
页面加载过慢或不完全:如果页面加载尚未完成或部分元素尚未加载,可能会导致元素不可见或不可交互。您可以使用适当的等待机制(如
WebDriverWait
)来等待页面加载完全,然后再进行点击操作。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC wait = WebDriverWait(driver, 10) # 设置最大等待时间为10秒 element = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "nui-btn-text"))) element.click()
-
定位正确的元素:如果找到的元素不是您要点击的实际元素,请确保使用准确的定位方式和选择器来定位目标元素。您可以尝试使用其他属性或组合属性来定位元素。
请结合具体情况,检查目标元素的状态和页面上的其他元素,以找到解决该异常的方法。我当时报的这个错,原因是元素被其他元素所覆盖,鼠标默认位置会产生浮动的元素遮挡了我要点击的内容,我使用ActionChains 类的方法将鼠标位置移到页面空白,就解决了这个问题。后来发现直接使用第一个方法的代码即可解决这个问题。
4、iframe标签的定位
在 Selenium 中对嵌入的 iframe 进行操作,就需要使用 switch_to.frame(frame_reference)
方法切换到该 iframe。frame_reference 常用的两种形式:
- 通过 frame 的索引进行切换:
driver.switch_to.frame(0) # 切换到第一个 iframe
- 通过 frame 的名称或 ID 进行切换:
通过 frame 的名称或 ID 进行切换:
driver.switch_to.frame("myframe") # 切换到名称或 ID 为 "myframe" 的 iframe
如果能确定该 iframe 标签在HTML网页中第几个iframe 标签,就可以使用第一种方法。第二种方法是先像定位其他普通标签一样定位到这个目标iframe ,然后进入iframe 标签。
切换到 iframe 后,你可以在该 iframe 中执行其他操作,比如查找元素、输入文本等。如果需要切换回最外层的页面,可以使用 switch_to.default_content() 方法。
附录
BeautifulSoup的find_all()方法
find_all()
方法是BeautifulSoup中最常用的方法之一,它用于根据选择器条件查找所有匹配的标签。下面详细介绍了find_all()
方法的使用:
find_all(name, attrs, recursive, string, limit, **kwargs)
参数说明:
name
:字符串、正则表达式、列表或True。用于指定标签名或多个标签名的集合。例如,name="div"
将返回所有<div>
标签。attrs
:字典或关键字参数。用于指定其他属性来筛选标签。例如,attrs={'class': 'example'}
将返回具有class
属性为example
的标签。recursive
:布尔值。指定是否在子孙节点中递归查找,默认为True。string
:字符串或正则表达式。用于筛选标签内包含指定文本的标签。limit
:整数。限制返回结果的数量。
除了上述参数外,还可以使用额外的关键字参数来进一步筛选标签,例如类名、ID等。
在使用BeautifulSoup库时,可以使用标签的相对位置来找到特定的标签。以下是几种常用的方法:
- find()和find_all()方法: 这两个方法可以根据标签名或其他属性来查找标签。例如,可以使用
find('div')
来查找第一个标签,或者使用find_all('a')
来查找所有 标签。 - parent、next_sibling和previous_sibling属性: 这些属性可以通过标签的相对位置来定位其他标签。例如,可以使用
tag.parent
来获取父级标签,使用tag.next_sibling
来获取下一个兄弟标签,使用tag.previous_sibling
来获取上一个兄弟标签。
当使用BeautifulSoup库时,可以利用以下的属性来定位标签的相对位置:
- parent:用于获取当前标签的父级标签。
parent_tag = tag.parent
示例中,tag
是当前标签的对象,通过.parent
属性可以得到其父级标签。
- next_sibling:用于获取当前标签的下一个兄弟标签。
next_sibling_tag = tag.next_sibling
示例中,tag
是当前标签的对象,通过.next_sibling
属性可以得到其下一个兄弟标签。
- previous_sibling:用于获取当前标签的上一个兄弟标签。
previous_sibling_tag = tag.previous_sibling
示例中,tag
是当前标签的对象,通过.previous_sibling
属性可以得到其上一个兄弟标签。
请注意,这些属性的使用有一些限制和特殊情况:
- 当前标签的父级/兄弟标签可能是空白字符、换行符等,并非具体的HTML标签。
- next_sibling和previous_sibling仅能获取直接的兄弟标签,如果需要获取所有兄弟标签,可以结合使用next_siblings和previous_siblings方法。
因此,在使用这些属性时,请确保对HTML结构和内容的了解,以便准确定位所需的标签。
常用正则表达式
正则表达式是用于匹配和处理文本的强大工具,下面列出了一些常见的正则表达式模式及其用途:
- 匹配数字:
\d
匹配任意一个数字。\d+
匹配一个或多个数字。\d{4}
匹配四个连续的数字。
- 匹配字母:
\w
匹配任意一个字母或数字或下划线。\w+
匹配一个或多个字母或数字或下划线。[a-zA-Z]
匹配一个英文字母。
- 匹配空白字符:
\s
匹配任意一个空白字符(空格、制表符、换行等)。\s+
匹配一个或多个空白字符。
- 匹配特定字符:
.
匹配除换行符外的任意一个字符。\[abc\]
匹配字符 a、b 或 c。[^0-9]
匹配除数字以外的任意一个字符。
- 匹配重复字符:
*
匹配零个或多个前面的表达式。+
匹配一个或多个前面的表达式。?
匹配零个或一个前面的表达式。{n}
匹配前面的表达式恰好 n 次。{n,}
匹配前面的表达式至少 n 次。{n,m}
匹配前面的表达式至少 n 次且不超过 m 次。
- 匹配开始和结束:
^
匹配字符串的开始。$
匹配字符串的结束。
以上只是一些常见的正则表达式模式示例,实际应用中还有更复杂的模式可以用于匹配特定的文本格式。你可以根据自己的需求和具体的文本数据进行定制化的正则表达式编写。
请注意,正则表达式对大小写敏感。如果需要忽略大小写,可以在正则表达式的开头添加 re.I
或 re.IGNORECASE
参数。