首页 > 其他分享 >爬虫之xpath模块,request-html模块,Selenium框架,

爬虫之xpath模块,request-html模块,Selenium框架,

时间:2024-07-17 21:42:54浏览次数:14  
标签:xpath title text request li html 模块 div

Ⅰ 爬虫之xpath模块

【一】xpath引言

【1】介绍

  • xpath在Python的爬虫学习中,起着举足轻重的地位,对比正则表达式 re两者可以完成同样的工作,实现的功能也差不多,但xpath明显比re具有优势,在网页分析上使re退居二线。
  • xpath 全称为XML Path Language 一种小型的查询语言

【2】优点

  • 可在XML中查找信息
  • 支持HTML的查找
  • 通过元素和属性进行导航
  • python开发使用XPath条件: 由于XPath属于lxml库模块,所以首先要安装库lxml

【3】安装

pip install lxml

【4】使用

from lxml import etree

# 将源码转化为能被XPath匹配的格式
selector=etree.HTML("源码") 

# 返回为一列表
selector.xpath("表达式")

【二】路径表达式

表达式 描述 实例 解析
/ 从根节点选取 /body/div[1] 选取根结点下的body下的第一个div标签
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 //a 选取文档中所有的a标签
./ 当前节点再次进行xpath ./a 选取当前节点下的所有a标签
@ 选取属性 //@calss 选取所有的class属性
# 如果是 soup对象 .attrs.get("href")
# 如果是 tree对象  xpath("./a/@href")

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>
</body>
</html>
"""
from lxml import etree

tree = etree.HTML(html_doc)

# 利用 tree 对象写语法
a_list= tree.xpath("/html/body/p/a")
for a in a_list:
    href = a.xpath("./@href")
    text = a.xpath("./text()")
    print(href)
    print(text)

# ['http://example.com/elsie']
# ['Elsie']
# ['http://example.com/lacie']
# ['Lacie']
# ['http://example.com/tillie']
# ['Tillie']

【三】谓语(Predicates)

  • 谓语用来查找某个特定的节点或者包含某个指定的值的节点。
  • 谓语被嵌在方括号中。
  • 在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式 结果
/ul/li[1] 选取属于 ul子元素的第一个 li元素。
/ul/li[last()] 选取属于 ul子元素的最后一个 li元素。
/ul/li[last()-1] 选取属于 ul子元素的倒数第二个 li元素。
//ul/li[position()❤️] 选取最前面的两个属于 ul元素的子元素的 li元素。
//a[@title] 选取所有拥有名为 title的属性的 a元素。
//a[@title='xx'] 选取所有 a元素,且这些元素拥有值为 xx的 title属性。
//a[@title>10] > < >= <= != 选取 a元素的所有 title元素,且其中的 title元素的值须大于 10。
/body/div[@price>35.00] 选取body下price元素值大于35的div节点

【四】选取未知节点

【1】语法

  • XPath 通配符可用来选取未知的 XML 元素。
通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

【2】实例

  • 在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 结果
/ul/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。
//node() 获取所有节点

【五】选取若干路径

【1】语法

  • 通过在路径表达式中使用 | 运算符,您可以选取若干个路径。

【2】实例

  • 在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 结果
//book/title | //book/price 选取 book 元素的所有 title 和 price 元素。
//title | //price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

(1)逻辑运算

//div[@id="head" and @class="s_down"] # 查找所有id属性等于head并且class属性等于s_down的div标签
//title | //price # 选取文档中的所有 title 和 price 元素,“|”两边必须是完整的xpath路径

(2)属性查询

//div[@id] # 找所有包含id属性的div节点
//div[@id="maincontent"]  # 查找所有id属性等于maincontent的div标签
//@class
//li[@name="xx"]//text()  # 获取li标签name为xx的里面的文本内容

(3)获取第几个标签 索引从1开始

tree.xpath('//li[1]/a/text()')  # 获取第一个
tree.xpath('//li[last()]/a/text()')  # 获取最后一个
tree.xpath('//li[last()-1]/a/text()')  # 获取倒数第二个

(4)模糊查询

//div[contains(@id, "he")]  # 查询所有id属性中包含he的div标签
//div[starts-with(@id, "he")] # 查询所有id属性中包以he开头的div标签

//div/h1/text()  # 查找所有div标签下的直接子节点h1的内容
//div/a/@href   # 获取a里面的href属性值 
//*  #获取所有
//*[@class="xx"]  #获取所有class为xx的标签

# 获取节点内容转换成字符串
c = tree.xpath('//li/a')[0]
result=etree.tostring(c, encoding='utf-8')
print(result.decode('UTF-8'))

【六】案例

from lxml import etree

doc = '''
<html>
 <head>
  <base href='http://example.com/' />  <!-- 设置基准链接 -->
  <title>Example website</title>  <!-- 设置网页标题 -->
 </head>
 <body>
  <div id='images'>
   <a href='image1' id='lqz'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <a href='image2'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5' class='li li-item' name='items'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
   <a href='image6' name='items'><span><h5>test</h5></span>Name: My image 6 <br /><img src='image6_thumb.jpg' /></a>
  </div>
 </body>
</html>
'''

# 将HTML字符串转为可解析的对象
html = etree.HTML(doc)

# 1. 获取所有节点
all_nodes = html.xpath('//*')
print(all_nodes)

# 2. 指定节点(结果为列表)
head_node = html.xpath('//head')
print(head_node)

# 3. 子节点和子孙节点
child_nodes = html.xpath('//div/a')  # 获取div下的所有a标签
descendant_nodes = html.xpath('//body//a')  # 获取body下的所有子孙a标签
print(child_nodes)
print(descendant_nodes)

# 4. 父节点
parent_node = html.xpath('//body//a[1]/..')  # 获取第一个a标签的父节点
print(parent_node)

# 5. 属性匹配
matched_nodes = html.xpath('//body//a[@href="image1"]')  # 获取href属性为"image1.html"的a标签
print(matched_nodes)

# 6. 文本获取
text = html.xpath('//body//a[@href="image1"]/text()')  # 获取第一个a标签的文本内容
print(text)

# 7. 属性获取
href_attributes = html.xpath('//body//a/@href')  # 获取所有a标签的href属性值
print(href_attributes)

# 8. 属性多值匹配
li_class_nodes = html.xpath('//body//a[contains(@class, "li")]')  # 获取class属性包含"li"的a标签
print(li_class_nodes)

# 9. 多属性匹配
matched_nodes = html.xpath('//body//a[contains(@class, "li") and @name="items"]')  # 获取class属性包含"li"和name属性为"items"的a标签
print(matched_nodes)

# 10. 按序选择
second_a_text = html.xpath('//a[2]/text()')  # 获取第二个a标签的文本内容
print(second_a_text)

# 11. 节点轴选择
ancestors = html.xpath('//a/ancestor::*')  # 获取a标签的所有祖先节点
div_ancestor_node = html.xpath('//a/ancestor::div')  # 获取a标签的祖先节点中的div
attribute_values = html.xpath('//a[1]/attribute::*')  # 获取第一个a标签的所有属性值
child_nodes = html.xpath('//a[1]/child::*')  # 获取第一个a标签的所有子节点
descendant_nodes = html.xpath('//a[6]/descendant::*')  # 获取第六个a标签的所有子孙节点
following_nodes = html.xpath('//a[1]/following::*')  # 获取第一个a标签之后的所有节点
following_sibling_nodes = html.xpath('//a[1]/following-sibling::*')  # 获取第一个a标签之后的同级节点

print(ancestors)
print(div_ancestor_node)
print(attribute_values)
print(child_nodes)
print(descendant_nodes)
print(following_nodes)
print(following_sibling_nodes)

【案例】jd爬取一些phone信息

  • jd.html 是你加Cookie之后拿到的页面数据 保存到本地
# 京东
import requests
from fake_useragent import UserAgent
from lxml import etree


class SpiderJD(object):
    def __init__(self):
        self.headers = {
            "User-Agent": UserAgent().random,
            "Cookie": "",
        }

    def save(self, data):
        with open("jd.html", "w", encoding="utf-8") as fp:
            fp.write(data)

    def read(self):
        with open("jd.html", "r", encoding="utf-8") as fp:
            data = fp.read()
        return data

    def spider_page_tree(self):

        target_url = 'https://search.jd.com/Search'

        params = {
            "keyword": "手机"
        }

        response = requests.get(url=target_url, headers=self.headers, params=params)

        page_text = response.text
        # self.save(data=page_text)
        # page_text = self.read()
        tree = etree.HTML(page_text)
        return tree

    def parse_good_data(self):
        tree = self.spider_page_tree()
        li_list = tree.xpath('//*[@id="J_goodsList"]/ul/li')
        good_data = {}
        for li in li_list:
            # //*[@id="J_goodsList"]/ul/li[2]/div/div[3]/strong/i
            # ./div/div[3]/strong/i
            price = li.xpath("./div/div[3]/strong/i/text()")[0]

            # //*[@id="J_goodsList"]/ul/li[2]/div/div[4]/a/em
            # ./div/div[4]/a/em
            title = li.xpath("./div/div[4]/a/em/text()")[0]

            # //*[@id="J_goodsList"]/ul/li[2]/div/div[7]/span/a
            # ./div/div[7]/span/a
            try:
                store = li.xpath("./div/div[7]/span/a/text()")[0]
            except Exception as e:
                store = ""

            try:
                # //*[@id="J_pro_100078020164"]
                # /html/body/div[5]/div[2]/div[2]/div[1]/div/div[2]/ul/li[8]/div/div[8]
                # ./div/div[8]
                tag = [i.xpath("./text()")[0] for i in li.xpath("./div/div[8]/i")]
            except Exception as e:
                tag = ""
            good_data[title] = {
                "price": price,
                "store": store,
                "tag": tag,
            }

        print(good_data)


if __name__ == '__main__':
    s = SpiderJD()
    s.parse_good_data()

【案例】豆瓣Top250基于xpath解析

import requests
from lxml import etree

url = "https://movie.douban.com/top250?start=0"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36"
}
resp = requests.get(url, headers=headers)

tree = etree.HTML(resp.text)  # 加载页面源代码

items = tree.xpath('//li/div[@class="item"]/div[@class="info"]')

for item in items:
    title = item.xpath('./div[@class="hd"]/a/span[1]/text()')[0]
    rating_num = item.xpath('./div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()')[0]
    comment_num = item.xpath('./div[@class="bd"]/div[@class="star"]/span[4]/text()')[0]
    print(title, rating_num, comment_num)

Ⅱ request-html模块

【一】引言

  • 作者致力于封装更好用的代码
    • 使用requests封装了python内置模块urllib
  • 经过重构又封装了 requests+lxml
    • requests+lxml 爬取 + 解析 合二为一
  • requests-html库是一个Python实现的网页解析库,它使用了Requests和BeautifulSoup库的组合,为用户提供了简单而强大的网页解析功能。

【二】安装

  • 可以使用pip命令安装requests-html库
pip install requests-html

【三】导入

  • 导入requests-html库,并创建HTMLSession对象
from requests_html import HTMLSession

session = HTMLSession()

【四】发送请求

  • 使用session对象发送HTTP请求,获取网页内容
response = session.get('http://example.com')

【五】解析网页

  • 可以使用.html属性将网页内容解析为BeautifulSoup对象
soup = response.html

【六】查找元素

  • 可以使用CSS选择器或XPath表达式在网页中查找元素
# 使用CSS选择器
elements = soup.find('div.classname')

# 使用XPath表达式
elements = soup.xpath('//div[@class="classname"]')

【七】提取数据

  • 可以通过元素对象的属性或方法提取相应的数据
# 提取文本内容
text = element.text

# 提取属性值
attribute = element.attrs['attribute_name']

【八】案例及注解

【1】方式一:CSS选择器语法

# 导入模块
from requests_html import HTMLSession
from fake_useragent import UserAgent

# 创建 HTMLSession 对象
session = HTMLSession()

# 定义目标地址
tag_url = "https://www.baidu.com/"

# 定义请求头参数
headers = {
    "User-Agent": UserAgent().chrome
}

# 发请求,获取响应数据
response = session.get(url=tag_url, headers=headers)

# 解析网页源码数据
soup = response.html

# 查看页面源码数据,字符串格式
# print(response.text)

# 【一】方式一:查找元素并提取数据
# 【1】使用CSS选择器查找ul元素
ul_list = soup.find('ul')
# print(ul_list)
# [<Element 'ul' id='mMenu'>, <Element 'ul' class=('s-hotsearch-content',) id='hotsearch-content-wrapper'>]

# 【2】获取当前 ul 标签下的所有li标签
li_list = ul_list[1].find("li")
# print(li_list)
# [<Element 'li' class=('hotsearch-item', 'odd') data-index='0'>, <Element 'li' class=('hotsearch-item', 'even') data-index='3'>, <Element 'li' class=('hotsearch-item', 'odd') data-index='1'>, <Element 'li' class=('hotsearch-item', 'even') data-index='4'>, <Element 'li' class=('hotsearch-item', 'odd') data-index='2'>, <Element 'li' class=('hotsearch-item', 'even') data-index='5'>]

data_list = []
# 【3】遍历每一个li标签
for li in li_list:
    # 【4】获取当前 li 标签下 的 a 标签的 href 属性
    href = li.find("a")[0].attrs["href"]
    # 【5】获取当前 li 标签下 的 a 标签 下 的 span 标签 的文本
    title = li.find("a > span.title-content-title")[0].text
    data_list.append({
        "title": title,
        "href": href,
    })
print(data_list)

【2】方式二:xpath语法

# 导入模块
from requests_html import HTMLSession
from fake_useragent import UserAgent

# 创建 HTMLSession 对象
session = HTMLSession()

# 定义目标地址
tag_url = "https://www.baidu.com/"

# 定义请求头参数
headers = {
    "User-Agent": UserAgent().chrome
}

# 发请求,获取响应数据
response = session.get(url=tag_url, headers=headers)

# 解析网页源码数据
soup = response.html

# 查看页面源码数据,字符串格式
# print(response.text)

# 【二】方式二:使用xpath方法提取所有的li标签数据
li_list = soup.xpath('//*[@id="hotsearch-content-wrapper"]/li')
data_list = []
for li in li_list:
    href = li.xpath("//a/@href")[0]
    title = li.xpath('//a/span[@class="title-content-title"]/text()')[0]
    data_list.append({
        "title": title,
        "href": href,
    })
print(data_list)

Ⅲ Selenium框架

【一】Selenium框架介绍

【1】web自动化

  • 随着互联网的发展,前端技术也在不断变化,数据的加载方式也不再是单纯的服务端渲染了。
    • 现在你可以看到很多网站的数据可能都是通过接口的形式传输的,
    • 或者即使不是接口那也是一些 JSON 的数据,然后经过 JavaScript 渲染得出来的。
  • 这时,如果你还用 requests 来爬取内容,那就不管用了。
    • 因为 requests 爬取下来的只能是服务器端网页的源码,这和浏览器渲染以后的页面内容是不一样的。
    • 因为,真正的数据是经过 JavaScript 执行后,渲染出来的,数据来源可能是 Ajax,也可能是页面里的某些 Data,或者是一些 ifame 页面等。
    • 不过,大多数情况下极有可能是 Ajax 接口获取的。
  • 所以,很多情况我们需要分析 Ajax请求,分析这些接口的调用方式,通过抓包工具或者浏览器的“开发者工具”,找到数据的请求链接,然后再用程序来模拟。
    • 但是,抓包分析流的方式,也存在一定的缺点。
    • 因为有些接口带着加密参数,比如 token、sign 等等,模拟难度较大;
  • 那有没有一种简单粗暴的方法,
    • 这时 Puppeteer、Pyppeteer、Selenium、Splash 等自动化框架出现了。
    • 使用这些框架获取HTML源码,这样我们爬取到的源代码就是JavaScript 渲染以后的真正的网页代码,数据自然就好提取了。
    • 同时,也就绕过分析 Ajax 和一些 JavaScript 逻辑的过程。
    • 这种方式就做到了可见即可爬,难度也不大,同时适合大批量的采集。

【2】Selenium优缺点

  • 作为一款知名的Web自动化测试框架,支持大部分主流浏览器,提供了功能丰富的API接口,常常被我们用作爬虫工具来使用。
  • 然而selenium的缺点也很明显
    • 速度太慢
    • 对版本配置要求严苛
    • 最麻烦是经常要更新对应的驱动
  • selenium最初是一个自动化测试工具,
    • 而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题
    • selenium本质是通过驱动浏览器,完全模拟浏览器的操作,
    • 比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器

【二】Selenium框架安装

【1】安装selenium包

pip install selenium
  • 首次安装会有进度条,而且装出来是多个包(依赖于其他第三方库)。
  • 如果安装慢(默认连接官网),可以指定国内源。
pip install selenium -i https://mirrors.aliyun.com/pypi/simple/

【2】安装chrome驱动

  • 选择与你浏览器版本差不多的 ,以及电脑配置一样的版本

# windows系统下载网址:https://storage.googleapis.com/chrome-for-testing-public/126.0.6478.182/win64/chromedriver-win64.zip
# MacOS系统:https://storage.googleapis.com/chrome-for-testing-public/126.0.6478.182/mac-arm64/chromedriver-mac-arm64.zip
# 解压后,将chromedriver文件复制到python安装目录下的Scripts文件夹中

【3】测试驱动

# 引入模块
from selenium.webdriver import Chrome
# 引入 Service
from selenium.webdriver.chrome.service import Service
import time
# 创建一个 service 对象
# Service(executable_path="驱动的地址")
service = Service(executable_path="./chromedriver.exe")

# 生成浏览器对象
browser = Chrome(
    service=service
)

# 控制浏览器打开百度
browser.get('https://www.baidu.com')

# 睡一会
time.sleep(3)

【4】案例

import time

# 引入 selenium
from selenium.webdriver import Chrome
# 引入service
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By

# 创建一个 浏览器对象
browser = Chrome(service=Service('./chromedriver.exe'))

# 打开一个网页
browser.get('https://www.baidu.com/')

# 找找指定标签的位置
input_search = browser.find_element(By.ID, "kw")

# 向输入框内输入内容
input_search.send_keys('Python')

time.sleep(3)

# 点搜索 ---> 先获取到搜索按钮
btn_search = browser.find_element(By.ID, "su")

# 让搜索标签回车或者点一下
btn_search.click()

time.sleep(3)

# 截屏
browser.save_screenshot('./baidu.png')

browser.close()

标签:xpath,title,text,request,li,html,模块,div
From: https://www.cnblogs.com/zyb123/p/18308335

相关文章

  • XD5012高速计数模块(差分)功能与选型及安装说明
    Profinet远程IO模块:XD5012高速计数模块(差分)功能与安装说明XD5012高速计数模块(差分)具有出色的计数功能,能够快速而精确地统计输入信号的数量。无论是频率计数、脉冲宽度测量还是时间测量,都能够轻松完成。这给各种应用场景提供了极大的便利,比如工业自动化控制。 本文将详细介绍X......
  • 在字符串的 格式化 与 反格式化 中用到的 模块 和 方法
    目录一,Open函数使用二,Json与pickle一,json模块1.将Python对象转换为JSON字符串2.将JSON字符串解析为Python对象3.读取和写入JSON文件4.处理JSON中的特殊数据类型5.错误处理二,pikel模块1.序列化Python对象2.反序列化Python对象3.处理自定义......
  • TS 入门(七):TypeScript模块与命名空间
    目录前言回顾泛型编程1.模块a.导入和导出b.默认导出c.重命名导入和导出2.命名空间a.定义命名空间b.嵌套命名空间3.动态导入与条件导入a.动态导入b.条件导入结语前言在前几章中,我们学习了TypeScript的基础知识、函数与对象类型、接口与类、以及泛型编......
  • Sqlmap中文使用手册 - Injection模块参数使用
    目录1.Injection模块的帮助文档2.各个参数的介绍2.1指定测试参数2.2--dbms=DBMS2.3--os=OS2.4--invalid-bignum2.5--invalid-logical2.6--invalid-string2.7--no-escape2.8--prefix/--suffix2.9--tamper=TAMPER1.Injection模块的帮助文档Injection:......
  • 7、nginx-日志模块的格式-log_format main、access.log(访问服务器记录的日志)
    日志模块的名称:ngx_http_log_module路径:vim/etc/nginx/nginx.conf相关指令:·日志格式:log_format---nginx有非常灵活的日志模式,每个级别的配置可以有各自独立的访问日志、日志格式通过log_format命令定义··语法Syntax:log_formatname[escape=default|json]......
  • Qt - QtWebEngineWidgets模块
    1、QtWebEngineWidgets模块 #include<QtWebEngineWidgets>QT+=webenginewidgets 1.1QWebEnginePage示例代码:#include<QtWebEngineWidgets>#include<QWebEnginePage>//1、创建一个新的QWebEnginePage实例:page=newQWebEnginePage(this);......
  • 在 Selenium 中,常见的元素定位方式有 ID、name、class_name、tag_name、link_text、pa
    在Selenium中,常见的元素定位方式有ID、name、class_name、tag_name、link_text、partial_link_text、XPath和CSS等。这些定位方式在不同的情况下都有各自的优缺点,以下是一些可能较为保险的元素定位方式:ID定位:通过元素的ID属性来定位元素。如果元素有唯一的ID,那么这......
  • 中科微电子ATGM336H GPS定位模块STM32应用
    文章目录前言1.中科微电子ATGM336H的使用1.1ATGM336H引脚说明1.2数据帧介绍1.3经纬度介绍1.4ATGM336H的启动方式2数据处理前置C语言知识2.1strstr函数2.2memset函数2.3memcpy函数2.4strtod函数3.开始移植3.1usart初始化程序3.2串口中断接收函数3.4数据帧......
  • 多种模块格式,包括 ES, CommonJS, UMD, AMD, SystemJS 和 IIFE的区别点分别是什么
    【转】https://zhuanlan.zhihu.com/p/668530823以下是各种模块格式的主要特点:ESModules(ESM):这是ECMAScript6(ES6)引入的官方标准格式。它支持导入和导出语句,以及静态分析和tree-shaking。它是唯一的静态模块系统,意味着你可以在编译时确定导入和导出的内容。CommonJS(C......
  • Pybind11和CMake构建python扩展模块环境搭建
    使用pybind11的CMake模板来创建拓展环境搭建从Github上下载cmake_example的模板,切换分支,并升级pybind11子模块到最新版本拉取pybind11使用cmake构建工具的模板仓库gitclone--recursivehttps://github.com/mrchipset/cmake_example.git切换分支gitcheckout-bdev升级s......