【爬虫】最全!selenium和pyppeteer看这一篇文章就够

这篇具有很好参考价值的文章主要介绍了【爬虫】最全!selenium和pyppeteer看这一篇文章就够。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

摘要:

思路:

区别:

一、selenium 简介

1.1、元素定位

1.2、属性选择器

1.3、定位方式选择

二、Pyppeteer简介

2.1、安装模块

2.2、等待机制和浏览器实例

2.3、常用的页面操作

执行js

元素操作

鼠标事件

键盘事件

内嵌框架

2.4、使用思路和案例

三、BeautifulSoup简介

3.1、安装模块

3.2、解析器

3.3、Beautiful Soup的使用

3.4、查找元素

1、遍历文档树

2、搜索文档树


摘要:

在写爬虫的时候,为了效率我们通常会选择解析网页api来获取数据,但是有时候解析方式比较困难(很多网站会对请求数据和返回数据加密),或者我们纯粹是为了快速实现爬虫,可使用浏览器自动化操作——selenium或pyppeteer。

思路:

对于爬取网站,一般有两种思路:

  1. 分析 Ajax 请求,通过模拟请求requests得到真实的数据,该情况受限于网站加密(可通过分析js加密解密函数来破解)
  2. 使用 selenium(或pyppeteer) 模拟浏览器进行动态渲染,从而获取网站返回的html内容,再通过Beautiful Soup4解析获得想要的数据。以下我们将详细讲解这种方法

区别:

selenium和pyppeteer都是模拟浏览器进行渲染,它们的区别如下:

  1. 环境配置:selenium使用起来是不太方便的,要安装浏览器、下载对应的驱动,而且各个工具的版本还要匹配,大规模部署时就比较麻烦;pyppeteer提供自动化下载chromium浏览器(支持浏览器比较单一),省去了 driver 配置的环节
  2. 语法结构:pyppeteer基于异步编程思想(使用asyncio构建),所以在使用的时候需要用到 async/await 结构。selenium是同步编程,则没有这些要求。
  3. 性能方面:pyppeteer基于协程,性能上会比selenium更高。

一、selenium 简介

selenium 就是一个用于 Web 应用程序的测试工具
根据官方文档所说,selenium 最大的优点就是它可以直接运行在浏览器上,模拟用户的真实行为
但同时这也是它最大的缺点,由于需要模拟真实的渲染过程,所以导致它的运行速度变慢

无论是selenium还是pyppeteer,都可以结合beautifulsoup使用。只需获取html源代码后,丢入beautifulsoup解析即可

1.1、元素定位

使用的时候需要导入By模块

 from selenium.webdriver.common.by import By

定位元素 find_element_by_* find_element()
通过元素id定位 find_element_by_id(x) find_element(By.ID,x)
通过元素name定位 find_element_by_name(x) find_element(By.NAME,x)
通过xpath表达式定位 find_element_by_xpath(x) find_element(By.XPATH,x)
通过完整超链接定位 find_element_by_link_text(x) find_element(By.LINK_TEXT,x)
通过部分链接定位 find_element_by_partial_link_text(x) find_element(By.PARTIAL_LINK_TEXT,x)
通过标签定位 find_element_by_tag_name(x) find_element(By.TAG_NAME,x)
通过类名进行定位 find_element_by_class_name(x) find_element(By.CLASS_NAME,x)
通过css选择器进行定位 find_element_by_css_selector(x) find_element(By.CSS_SELECTOR,x)

定位多个元素,就是把上述element后面多了复数标识s,变为elements,其他操作一致。

以上的操作可以等同于以下:

find_element_by_xx find_elements_by_xx
没有匹配到元素 执行报错 返回空列表
匹配到一个元素 返回元素 返回包含一个元素的列表
匹配到多个元素 返回第一个元素 返回包含所有匹配元素列表
from selenium.webdriver.common.by import By
element = web.find_element(By.ID,'kw')
element = web.find_element(By.NAME,'wd')
element = web.find_element(By.CLASS_NAME,'s_ipt')
element = web.find_element(By.TAG_NAME,'input')
element = web.find_element(By.LINK_TEXT,'新闻')
element = web.find_element(By.PARTIAL_LINK_TEXT,'闻')
element = web.find_element(By.XPATH,'//*[@id="kw"]')
element = web.find_element(By.CSS_SELECTOR,'#kw')
element = web.find_element(By.CSS_SELECTOR,'[id="kw"]')
element = web.find_element(By.CSS_SELECTOR,'input[id="kw"]')

目前,由于selenium版本升级,使用find_element_by_*,会提示弃用警告,建议使用find_element()。

DeprecationWarning: find_element_by_* commands are deprecated. Please use find_element()

1.2、属性选择器

根据标签中的属性来定位元素, 格式: [属性名=”属性值”],或标签名[属性名=属性值]。如果属性是唯一的,那么标签名可以不用写。如下:

<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">

元素定位如下:

element = web.find_element_by_css_selector('[id="kw"]') 
element = web.find_element_by_css_selector('input[id="kw"]') 
#定位复合class属性
element = web.find_element_by_css_selector('[class="s-top-left-new s-isindex-wrap"]')

1.3、定位方式选择

  • 当页面元素有id属性时,尽量用id来定位;
  • 当有链接需要定位时,可以考虑link text或partial link text方式;
  • 当要定位一组元素相同元素时,可以考虑用tag name或class name;
  • css selector定位速度比较快,效率高。
  • 一般id>name>css>XPath

安装和基础语法参考:Selenium:强烈推荐!内含最详细的介绍[安装,基本使用]

鼠标和键盘操作参考:Selenium中鼠标、键盘等操作

设置js加载等待时间参考:Selenium的三种等待,强制等待、隐式等待、显式等待

二、Pyppeteer简介

pyppeteer是puppeteer的Python版本,而puppeteer是什么呢?puppeteer是Google基于Node.js开发的一个工具,它可以使我们通过JavaScript来控制Chrome浏览器执行一些操作,拥有丰富的API,功能非常强大,因此也可以用于网络爬虫。pyppeteer是一位日本的程序员根据Puppeteer开发的非官方Python版本。

2.1、安装模块

pip install pyppeteer

# 使用时导入
import pyppeteer

2.2、等待机制和浏览器实例

page.waitForXPath等待 xPath 对应的元素出现,返回对应的 ElementHandle 实例

page.waitForSelector :等待选择器对应的元素出现,返回对应的 ElementHandle 实例

启动器

  • pyppeteer.launcher.launch()
    启动 Chrome 进程并返回浏览器实例

参数:

参数 类型 解释
ignoreHTTPSErrors bool 是否忽略 HTTPS 错误。默认为 False
ignoreDefaultArgs List [str] 不要使用 pyppeteer 的默认参数。这是危险的选择;小心使用
headless bool 无头模式下运行浏览器。默认为 True 除非 appModedevtools 选项 True
executablePath str 运行 Chromium 或 Chrome 可执行文件的路径,而不是默认捆绑的 Chromium
slowMo int或float 按指定的毫秒数减慢 pyppeteer 操作。
args List [str] 传递给浏览器进程的附加参数(标志)。
dumpio bool 是否管道浏览器进程 stdout 和 stderr 进入 process.stdoutprocess.stderr。默认为 False。
userDataDir str 用户数据目录的路径
env dict 指定浏览器可见的环境变量。默认与 python 进程相同。
devtools bool 为每个选项卡自动打开 DevTools 面板。如果是此选项 Trueheadless 则将设置该选项 False
logLevel int或str 用于打印日志的日志级别。默认值与根记录器相同。
autoClose bool 脚本完成时自动关闭浏览器进程。默认为 True
loop asyncio.AbstractEventLoop 事件循环(实验)。

移除Chrome正受到自动测试软件的控制,可直接绕过浏览器window.navigator.webdriver检测

# 添加ignoreDefaultArgs=["--enable-automation"] 参数
from pyppeteer import launch
browser = await launch(headless=False, ignoreDefaultArgs=["--enable-automation"])

浏览器的console运行如下代码,同正常打开浏览器一样都为undefined,如果不设置就为true

【爬虫】最全!selenium和pyppeteer看这一篇文章就够

【爬虫】最全!selenium和pyppeteer看这一篇文章就够

2.3、常用的页面操作

执行js

page.evaluate ( pageFunction [, …args] ) ,返回 pageFunction 执行的结果,pageFunction 表示要在页面执行的函数或表达式, args 表示传入给 pageFunction 的参数

课外内容

scrollTo和scrollBy这两个JS API也是用来控制元素或者窗体的滚动距离的。

scrollTo()表示滚到到指定的位置,而scrollBy()表示相对当前的位置滚动多少距离。

scrollTo和scrollBy两个JS API的优点有两个:

  1. 调用统一
    scrollLeft/scrollTop这两个属性只能作为元素上,在window对象上没有效果。而pageXOffset/pageYOffset只能作用于window对象上,在元素上没有效果。而scrollTo和scrollBy不仅可以作用于window对象上,还可以作用于元素上。实现的调用的统一。
  2. 平滑支持
    scrollLeft/scrollTop和pageXOffset/pageYOffset控制滚动定位,想要定位平滑,只能借助于CSS scroll-behavior属性,JS这块设置无力。但是scrollTo和scrollBy在比较方便,直接有API参数支持。

代码

scroll_top = 100

await page.evaluate(f'document.getElementsByClassName("mp-layout-content-container")[0].scrollBy(0, {scroll_top})')

元素操作

ElementHandle 表示页内的DOM元素,你可以通过 page.querySelector() 方法创建。DOM 元素具有和 page 相同的某些方法:J()、JJ()、Jeval()、JJeval()、screenshot()、type()、click()、tap()。此外,还有一些好用的方法:

(1) 获取元素边界框坐标:boundingBox(),返回元素的边界框(相对于主框架)=> x 坐标、 y 坐标、width、height

(2) 元素是否可见:isIntersectingViewport()

(3) 上传文件:uploadFile(*filpaths)

(4) ElementHandle 类 转 Frame类:contentFrame(),如果句柄未引用iframe,则返回None。

(5) 聚焦该元素:focus()

(6) 与鼠标相关:hover () ,将鼠标悬停到元素上面

(7) 与键盘相关:press (key[, options]),按键,key 表示按键的名称,option可配置:

    text (string) - 如果指定,则使用此文本生成输入事件

    delay (number) - keydown 和 keyup 之间等待的时间。默认是 0

鼠标事件

Mouse 类在相对于视口左上角的主框架 CSS 像素中运行。

(1) page.mouse.down([options]) 按下鼠标,options 可配置:

    button(str) 按下了哪个键,可选值为 [ left, right, middle ], 默认是 left, 表示鼠标左键

    clickCount(int) 按下的次数,单击,双击或者其他次数

(2) page.mouse.up([options]) 松开鼠标,options 同上

(3) page.mouse.move(x, y, [options]) 移动鼠标到指定位置,options.steps 表示移动的步长

(4) page.mouse.click(x, y, [options]) 鼠标点击指定的位置,其实是 mouse.move 和 mouse.down 或 mouse.up 的快捷操作

键盘事件

Keyboard 提供一个接口来管理虚拟键盘. 高级接口为 keyboard.type, 其接收原始字符, 然后在你的页面上生成对应的 keydown, keypress/input, 和 keyup 事件。

为了更精细的控制(虚拟键盘), 你可以使用 keyboard.down, keyboard.up 和 keyboard.sendCharacter 来手动触发事件, 就好像这些事件是由真实的键盘生成的。

键盘的几个API如下:

    keyboard.down(key[, options]) 触发 keydown 事件
    keyboard.press(key[, options]) 按下某个键,key 表示键的名称,比如‘ArrowLeft’ 向左键;
    keyboard.sendCharacter(char) 输入一个字符
    keyboard.type(text, options) 输入一个字符串
    keyboard.up(key) 触发 keyup 事件

详细的键名映射可以看源码
Lib\site-packages\pyppeteer\us_keyboard_layout.py

内嵌框架

可以通过 Page.frames、ElementHandle.contentFrame 方法获取,同时具有和 page一样的多个方法;

**其它:

    childFrames 获取子框架,返回列表
    parentFrame 返回父框架
    content() 返回框架的 html 内容
    url 获取 url
    name 获取 name
    title() 获取 title

更多内容可参考:Pyppeteer库之四:Pyppeteer的页面操作

2.4、使用思路和案例

无论是使用Selenium还是Pyppeteer原理都是模拟浏览器进行加载js渲染页面,所以我们最后要拿到经过渲染后的网页源代码,再结合Beautiful Soup进行html标签元素解析提取

在Pyppeteer中,它操作的是一个类似Chrome的Chromium浏览器,Chromium是相当于Chrome的开发版,是完全开源的,Chrome的所有新功能都会先在Chromium上实现,稳定后才会移植到Chrome上,因此Chromium会包含很多新功能。Pyppeteer就是依赖于Chromium来运行的,当我们第一次运行Pyppeteer的时候,如果Chromium没有安装,那么程序会自动帮我们安装和配置,省去了环境配置这一步。

下面我们详细了解一下Pyppeteer的使用思路。

  1. aunch 方法新建一个Browser对象,赋值给browser变量,这一步就相当于启动了浏览器
  2. 然后browser调用newPage方法相当于新建一个选项卡,并且返回一个Page对象,这一步还是一个空白的页面,并未访问任何页面
  3. 然后Page调用goto方法,就相当于访问此页面
  4. Page对象调用waitForXpath方法,那么页面就会等待选择器所对应的节点信息加载出来,如果加载出来就立即返回,否则就会持续等待直到超时。这里就比selenium的等待元素加载完毕要清晰的多了。
  5. 页面加载完成后再调用content方法,获取渲染出来的页面源代码
  6. 通过BeautifulSoup解析源代码,提取需要的数据

例子:

# -*- coding: utf-8 -*-
"""
@Time : 2023/1/5 11:22 AM
@File :web_to_excel.py
"""
import datetime
import os.path
import time

import requests
from bs4 import BeautifulSoup
import xlrd
from xlutils.copy import copy
import asyncio
from pyppeteer import launch
import lxml


async def main(cookies_str):
    html_source = await collect_data(cookies_str)
    table_data = await parse_html(html_source)
    await write_excel_data(table_data)




async def collect_data(cookies_str):
    cookies = []
    for i in cookies_str.split(';'):
        print(i)
        tmp = i.split('=', 1)
        cookie = {"name": tmp[0].strip(), "value": tmp[1].strip()}
        cookies.append(cookie)

    conf_dict = {
        'autoClose': True,
        'headless': False,
        'dumpio': True,
        'ignoreDefaultArgs': ["--enable-automation"] # 移除Chrome正受到自动测试软件的控制
    }
    browser = await launch(conf_dict)
    page = (await browser.pages())[0]

    # 是否启用JS,enabled设为False,则无渲染效果
    await page.goto('需要爬取的网站')

    # print('current cookies', page.cookies())
    # 刷新网页
    await page.setCookie(*cookies)
    await page.reload()
    # await asyncio.sleep(10)
    await page.waitForSelector('.mp-table')  # 等待节点出现
    html_source = await page.content()
    # print(type(html_source), html_source)
    return html_source


async def parse_html(html_source):
    soup = BeautifulSoup(html_source, 'lxml')
    div_table_html = soup.find_all('div', attrs={'class': 'slate-card'})[1]  # 找到第二个表格
    title_tr = div_table_html.find('tr', attrs={'class': 'mp-table-row-sticky'})  # 标题的标签
    title_td = title_tr.find_all('td')
    title_text = []
    for t_td in title_td:
        cell_span = t_td.find_all('span', attrs={'data-slate-string': 'true'})  # 标题的文本
        cell_str = '\n'.join([c_span.text for c_span in cell_span])
        title_text.append(cell_str)
    print(111, len(title_text), title_text)  # 标题

    content_text = []  # 内容:是个二维列表
    for other_tr in title_tr.next_siblings:
        other_td = other_tr.find_all('td')
        row_text = []
        for o_td in other_td:
            cell_span = o_td.find_all('span', attrs={'data-slate-string': 'true'})  # 内容的文本
            cell_str = '\n'.join([c_span.text for c_span in cell_span])
            row_text.append(cell_str)
        print(112, len(row_text), row_text)  # 内容
        content_text.append(row_text)

    # content_span = title_tr.next_siblings.find_all('span', attrs={'data-slate-string': 'true'}) #除标题外的其他行
    # content_text = [span.text for span in content_span]
    content_text.insert(0, title_text)
    print(222, content_text)
    return content_text


async def write_excel_data(data, save_path="/Users/Desktop/变更操作单"):
    # data: 二维数组,表示插入excel的数据
    # save_path: 工作簿的路径
    # formatting_info=True:保留Excel的原格式
    workbook = xlrd.open_workbook('/Users/Desktop/变更操作单/变更操作单模板.xls', formatting_info=True)

    new_workbook = copy(workbook)  # 将xlrd对象拷贝转化为xlwt对象

    print(workbook.sheets())

    # 写入表格信息
    # 第一次建立工作簿时候调用
    write_sheet = new_workbook.get_sheet(0)

    index = len(data)  # 获取需要写入数据的行数
    # workbook = xlwt.Workbook()  # 新建一个工作簿
    for i in range(0, index):
        for j in range(0, len(data[i])):
            write_sheet.write(i, j, data[i][j])  # 像表格中写入数据(对应的行和列)

    # now_date_str = time.strftime("%Y%m%d", time.localtime())
    now_date_str = '20230129'
    save_path = os.path.join(save_path, "{}变更操作单.xls".format(now_date_str))
    new_workbook.save(save_path)  # 保存工作簿


if __name__ == '__main__':
    # 需手动更新cookie
    cookies_str = '页面中获取'

    asyncio.get_event_loop().run_until_complete(main(cookies_str))

要实现用户自动登录,可获取浏览器cookie

 参考:获取cookies(pyppeteer)

还有另一种方法实现自动登录验证,即启动浏览器时,传入userDataDir参数即可:

conf_dict = {
    'userDataDir': "存放浏览记录的文件夹", #完成第一次手动输入验证,后续就不用再验证了
    'autoClose': False,
    'headless': False,
    'dumpio': True,
    'ignoreDefaultArgs': ["--enable-automation"]
}
browser = await launch(conf_dict)

三、BeautifulSoup简介

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过转换器实现惯用的文档导航、查找、修改文档的方式。Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4。

3.1、安装模块

# 安装 Beautiful Soup
pip install beautifulsoup4

# 安装解析器
pip install lxml

3.2、解析器

下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高。 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定。

解析器 使用方法 优势 劣势
Python标准库 BeautifulSoup(markup, "html.parser")
  • Python的内置标准库
  • 执行速度适中
  • 文档容错能力强
  • Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
lxml HTML 解析器 BeautifulSoup(markup, "lxml")
  • 速度快
  • 文档容错能力强
  • 需要安装C语言库
lxml XML 解析器

BeautifulSoup(markup, ["lxml", "xml"])

BeautifulSoup(markup, "xml")

  • 速度快
  • 唯一支持XML的解析器
  • 需要安装C语言库
html5lib BeautifulSoup(markup, "html5lib")
  • 最好的容错性
  • 以浏览器的方式解析文档
  • 生成HTML5格式的文档
  • 速度慢
  • 不依赖外部扩展

3.3、Beautiful Soup的使用

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
# 容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。
# 使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml') #具有容错功能
res=soup.prettify() #处理好缩进,结构化显
print(res)

3.4、查找元素

1、遍历文档树

# 遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""

from bs4 import BeautifulSoup
# 获取BeautifulSoup对象
soup=BeautifulSoup(html_doc,'lxml')

print(soup.p)     # 存在多个相同的标签则只返回第一个
print(soup.a)     # 存在多个相同的标签则只返回第一个

# 1. 获取标签的名称
print(soup.p.name)

# 2. 获取标签的属性
print(soup.p.attrs)

# 3. 获取标签的内容
print(soup.p.string)     # p下的文本只有一个时,取到,否则为None
print(soup.p.strings)      # 拿到一个生成器对象, 取到p下所有的文本内容,可以转换为list
print(soup.p.text)       # 取到p下所有的文本内容
for line in soup.stripped_strings:    # 去掉空白
    print(line)

# 4. 嵌套选择
print(soup.head.title.string)
print(soup.body.a.string)


# 5. 子节点、子孙节点
print(soup.p.contents)      # p下所有子节点
print(soup.p.children)      # 得到一个迭代器,包含p下所有子节点
for i,child in enumerate(soup.p.children):
    print(i,child)

print(soup.p.descendants) 	# 获取子孙节点,p下所有的标签都会选择出来
for i,child in enumerate(soup.p.descendants):
    print(i,child)

# 6. 父节点、祖先节点
print(soup.a.parent)  		# 获取a标签的父节点
print(soup.a.parents) 	    # 找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...


# 7. 兄弟节点
print(soup.a.next_sibling) 		# 下一个兄弟
print(soup.a.previous_sibling) 		# 上一个兄弟

print(list(soup.a.next_siblings)) 		# 下面的兄弟们=>生成器对象
print(soup.a.previous_siblings) 		# 上面的兄弟们=>生成器对象

2、搜索文档树

(1)五种过滤器

字符串正则表达式列表True方法

# 过滤器结合find() 和 find_all()方法使用查找元素
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>
</p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""

from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml')

# 1.字符串
print(soup.find_all('b'))

# 2.、正则表达式
# 利用re.compile()使用正则
import re
print(soup.find_all(re.compile('^b')))   # 找出b开头的标签,结果有body和b标签

# 3.列表:
# 如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签:
print(soup.find_all(['a','b']))

# 4.True
# 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
print(soup.find_all(True))
for tag in soup.find_all(True):
    print(tag.name)

# 5.方法
# 如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')

print(soup.find_all(has_class_but_no_id))

# 匿名函数
print(soup.find_all(lambda tag: True if tag.has_attr("class") and tag.has_attr("id") else False))

(2)find_all( name , attrs , recursive , text , **kwargs )

# 1、name: 搜索name参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True .
print(soup.find_all(name=re.compile('^t')))

# 2、keyword: key=value的形式,value可以是过滤器:字符串 , 正则表达式 , 列表, True .
print(soup.find_all(id=re.compile('my')))
print(soup.find_all(href=re.compile('lacie'),id=re.compile('d'))) #注意类要用class_
print(soup.find_all(id=True))    # 查找有id属性的标签

# 有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
# data_soup.find_all(data-foo="value") #报错:SyntaxError: keyword can't be an expression
# 但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:
print(data_soup.find_all(attrs={"data-foo": "value"}))
# [<div data-foo="value">foo!</div>]

# 3、按照类名查找,注意关键字是class_,class_=value,value可以是五种选择器之一
print(soup.find_all('a',class_='sister')) #查找类为sister的a标签
print(soup.find_all('a',class_='sister ssss')) #查找类为sister和sss的a标签,顺序错误也匹配不成功
print(soup.find_all(class_=re.compile('^sis'))) #查找类为sister的所有标签

# 4、attrs
print(soup.find_all('p',attrs={'class':'story'}))

# 5、text: 值可以是:字符,列表,True,正则
print(soup.find_all(text='Elsie'))
print(soup.find_all('a',text='Elsie'))

# 6、limit参数:如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果
print(soup.find_all('a',limit=2))

# 7、recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False
print(soup.html.find_all('a'))
print(soup.html.find_all('a',recursive=False))

(3)find( name , attrs , recursive , text , **kwargs )

唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None .
print(soup.find("nosuchtag"))
# None

soup.head.title 是 tag的名字 方法的简写.这个简写的原理就是多次调用当前tag的 find() 方法

(4)CSS选择器(select('.class'))文章来源地址https://www.toymoban.com/news/detail-460021.html

#该模块提供了select方法来支持css,详见官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id37
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title">
    <b>The Dormouse's story</b>
    Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">
        <span>Elsie</span>
    </a>
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    <div class='panel-1'>
        <ul class='list' id='list-1'>
            <li class='element'>Foo</li>
            <li class='element'>Bar</li>
            <li class='element'>Jay</li>
        </ul>
        <ul class='list list-small' id='list-2'>
            <li class='element'><h1 class='yyyy'>Foo</h1></li>
            <li class='element xxx'>Bar</li>
            <li class='element'>Jay</li>
        </ul>
    </div>
    and they lived at the bottom of a well.
</p>
<p class="story">...</p>
"""
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml')

# 1. CSS选择器
# select 返回的是一个列表
print(soup.p.select('.sister'))
print(soup.select('.sister span'))
print(soup.select('#link1'))
print(soup.select('#link1 span'))
print(soup.select('#list-2 .element.xxx'))

print(soup.select('#list-2')[0].select('.element'))  # 可以一直select,但其实没必要,一条select就可以了

# 2. 获取属性
print(soup.select('#list-2 h1')[0].attrs)

# 3. 获取内容
print(soup.select('#list-2 h1')[0].get_text())

到了这里,关于【爬虫】最全!selenium和pyppeteer看这一篇文章就够的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • tmux 使用看这一篇文章就够了

    tmux是一个终端复用工具,允许用户在一个终端会话中同时管理多个终端窗口,提高了终端使用效率,尤其在服务器上进行远程管理时更加实用。在tmux中,可以创建多个终端窗口和窗格,并在这些窗口和窗格之间自由切换,还可以在后台运行会话,即使在终端断开连接后也可

    2024年02月02日
    浏览(40)
  • 学java注解,看这一篇文章就够了

    Annotation(注解)是一种标记,使类或接口附加额外信息,帮助编译器和 JVM 完成一些特定功能。 Annotation(注解)也被称为元数据(Metadata)是JDK1.5及以后版本引入的,用于修饰 包、类、接口、字段、方法参数、局部变量 等。 常见的注解如:@Override、@Deprecated和@SuppressWarnings 2.1 使用步

    2024年02月06日
    浏览(27)
  • JavaWeb入门看这一篇文章就够了

    第1节 什么是web 第2节 什么是JavaWeb   第1节 JavaWeb服务器是什么 第2节 常见的JavaWeb服务器介绍 Tomcat当前最流行的web容器(免费) jetty(免费) Weblogic(收费) 第3节 Tomcat服务器 tomcat服务器介绍 tomcat的目录结构   tomcat的常用命令 tomcat的用户管理 tomcat的服务配置管理 在一台服务器上配

    2024年02月03日
    浏览(47)
  • 初级面试问到rabbitMQ,看这一篇文章就够了!

    一、rabbitMQ的基础要点回顾 1.使用场景 1) 解耦: 使用消息队列避免模块间的直接调用。将所需共享的数据放在消息队列中,对于新增的业务模块,只要对该类消息感兴趣就可以订阅该消息,对原有系统无影响,降低了各个模块的耦合度,提供系统的扩展性。 2) 异步: 消息

    2024年02月04日
    浏览(31)
  • 华为交换机端口隔离看这一篇文章就行了

    1.    实验目的 掌握端口隔离技术 2.    实验拓扑 华为数通HCIP-Datacom实验指南(全套实验操作)-学习视频教程-腾讯课堂 3.    实验步骤 配置IP地址    如图所示配置IP地址(此处省略) 创建VLAN,并把接口划入到VLAN [Huawei]sysname LSW1 [LSW1]vlan 10 [LSW1-vlan10]quit    [LSW1]vlan 20

    2024年02月07日
    浏览(28)
  • 关于腾讯云轻量应用服务器性能测评,看这一篇文章就够了

    腾讯云轻量应用服务器性能如何?为什么便宜是不是性能不行?腾讯云百科txybk.com从轻量应用服务器的CPU型号、处理器主频、内存、公网带宽、月流量和系统盘多方面来详细测评轻量性能,轻量应用服务器性价比高,并不是性能不行,只是限制每月流量,轻量还是很值得买的

    2024年02月08日
    浏览(32)
  • 【热门框架】Mybatis-Plus入门介绍看这一篇文章就足够了

    MyBatis-Plus 是在 MyBatis 的基础上进行了封装,提供了更加便捷的开发方式,具有简化开发、提高效率等优点。以下是 MyBatis-Plus 的一些特点和用法: 通用 CRUD 操作:MyBatis-Plus 提供了通用的 CRUD 接口,可以直接调用,无需再编写 SQL 语句。例如,可以通过继承 BaseMapper 接口来实现

    2024年02月02日
    浏览(30)
  • Python SQL 数据库操作利器:SQLAlchemy 库详解(看这一篇文章就够了)

    引言: Python 是一门广受欢迎的编程语言,而 SQL 则是用于管理和操作数据库的标准查询语言。SQLAlchemy 是一个功能强大的 Python 库,它提供了一种与多种数据库进行交互的灵活方式。本文将介绍 SQLAlchemy 库,并以九个重要的要点详细解释其功能和用法。 SQLAlchemy 简介 SQLAlchem

    2024年02月07日
    浏览(51)
  • 深入探索Python的scipy库:强大的科学计算工具集(学scipy看这一篇文章就够了)

    引言: Python是一种功能强大且受欢迎的编程语言,广泛应用于科学计算、数据分析和工程应用领域。在Python生态系统中,scipy库是一个重要的工具,提供了许多用于科学计算的高级功能。本文将深入探索scipy库,介绍其主要功能和用法,并提供相应的代码示例和相关资源。 一、

    2024年02月09日
    浏览(34)
  • DevOps是什么?只看这篇文章就够了!

    作者:沈洲 原文链接:DevOps是什么?只看这篇文章就够了!-云社区-华为云 作为一个热门的概念,DevOps这个名词在程序员社区里频频出现,备受技术大佬们的追捧。甚至网络上有了“南无DevOps”的戏言(南无在梵语的意思是“皈依”),也侧面反映了DevOps的风靡。 然而,一

    2024年02月21日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包