爬虫的基础知识下(Xpath解析和bs4解析)

164 阅读6分钟

Xpath解析

定义:

Xpath是XML路径语言,它可以用来确定xml文档中的元素位置,通过元素路径来完成对元素的查找。xpath是一种非常强大的定位方式。Path通常与lxml库一起使用,用于解析XML或HTML文档。

概念:

XPath 是一种用于在 XML 文档中导航和选择节点的查询语言,它基于一些核心概念:

  1. 节点(Nodes): 在XML文档中,所有的内容都被视为节点,包括元素、属性、文本、注释等。XPath 中的节点分为元素节点、属性节点、文本节点等。。
  2. 节点路径(Node Path): 节点路径是XPath中用于定位节点的一种表达方式。它描述了从文档根节点到目标节点的路径,以斜杠 / 分隔各级节点。
  3. 谓词(Predicate): 谓词是XPath中用于筛选节点的表达式,可以附加在节点路径的末尾,帮助进一步限定所选节点的条件。
  4. 表达式(Expression): XPath 表达式是一组语法规则,用于描述如何在XML文档中选择节点。这包括节点路径、运算符、函数等。
  5. 运算符(Operators): XPath 提供了一些运算符,用于在表达式中执行比较和计算操作,例如关系运算符(=、!=、<、>等)和逻辑运算符(and、or、not等)。
  6. 函数(Functions): XPath 支持一些内置函数,用于执行各种操作,例如字符串处理、数学运算等。函数通过名称和参数来调用。

节点之间的关系:

  • 父节点(Parent) : HTML 是 body 和 head 节点的父节点;
  • 子节点(Child) :head 和 body 是 HTML 的子节点;
  • 兄弟节点(Sibling) :拥有相同的父节点,head 和 body 就是兄弟节点。title 和 div 不是兄弟,因为他们不是同一个父节点。
  • 祖先节点(Ancestor) :body 是 form 的祖先节点,爷爷辈及以上👴;
  • 后代节点(Descendant) :form 是 HTML 的后代节点,孙子辈及以下👶。

html文档树

1679425993990-ffc26af3-f67f-4f61-9e80-4fc530b3bcb8.png

代码演示:

import requests
from lxml import etree
url='example.com'
headers='User-Agent':'example
response=requests.get(url=url,headers=headers)
# 创建etree对象
html=etree.HTML(response.text)
...

Xpath的定位语法

例:

1682408701170-91e04fb4-7e6b-47e0-b390-bdd0b6ae333b.png

绝对路径与相对路径

绝对路径定位语法:

Xpath 中的绝对路径从 HTML 根节点开始算,相对路径从任意节点开始。通过开发者工具,我们可以拷贝到 Xpath 的绝对路径和相对路径代码:

Xpath复制绝对路径图.png 同时绝对路径也是最直观的路径: /html/body/div[2]/div[1]/div[5]/div/div/form/span[1]/input

相对路径定位语法:
表达式说明举例
/从根节点开始选取/html/div/span
//从任意节点开始选取//input
.选取当前节点
..选取当前节点的父节点//input/.. 会选取 input 的父节点
@选取属性或者根据属性选取//input[@data] 选取具备 data 属性的 input 元素 //@data 选取所有 data 属性
*通配符,表示任意节点或任意属性

相对路径:

以//开头,可以从任意节点开始,一般我们会取一个唯一定位到的元素开始写,可以增加查找的准确性。 //*[@id="kw"]

# 从根节点开始定位
/html/body/div/form/div

# 从任意节点开始选取
//form/div

# 属性定位是通过 @ 符号指定需要使用的属性。
# class属性定位
//form/span[@class="soutu"]

# ID属性定位
//input[@id="su"]

# 使用谓语定位
# 元素下标定位
//form[@id="form"]/span[2]
#定位到form标签下的第二个span标签

//form[@id="form"]/span[last()]
#定位到form标签下的最后一个span标签

//form[@id="form"]/span[last()-1]
#定位到form下的倒数第二个span标签

//form[@id="form"]/span[position()=2]
#定位到from 下第二个span标签

//form[@id="form"]/span[position()>2]
#定位到form下的 下标大于 2 的span标签

使用部分匹配函数定位

函数说明举例
contains选取属性或者文本包含某些字符//div[contains(@id, 'data')] 选取 id 属性包含 data 的 div 元素
starts-with选取属性或者文本以某些字符开头//div[starts-with(@id, 'data')] 选取 id 属性以 data 开头的 div 元素

bs4解析

BeautifulSoup的基础应用

Beautiful Soup 是一个 Python 库,用于从 HTML 和 XML 文件中提取数据。它提供了一种方式来快速浏览文件的结构,找到我们需要的数据,并提供解析、遍历和修改文档树的方法。通常在网络爬虫、数据挖掘和数据分析等领域中使用。Beautiful Soup 支持多种解析器,包括 Python 的内置解析器和第三方库。它能够将复杂的 HTML 和 XML 文档转换为一个复杂的树形结构,每个节点都是一个 Python 对象,可以通过不同的方式进行遍历、搜索和修改。

一些文档解析器:

文档解析器.png

一些常见对象的种类:

  • tag : html中的标签。可以通过BeautifulSoup分析Tag的具体内容,具体格式为soup.name,其中name是html下的标签。
  • NavigableString : 标签中的文本对象。
  • BeautifulSoup : 整个html文本对象。可以作为Tag对象。
  • Comment : 特殊的NavigableString对象,如果html标签中有注释,则可过滤注释符号并保留注释文本。

代码演示

from bs4 import BeautifulSoup

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>
"""
#创建BeautifulSoup对象
soup=BeautifulSoup(httml_doc,'lxml')
print(type(soup)) # 输出<class 'bs4.BeautifulSoup'> 
print(type(soup.body)) # 输出 <class 'bs4.element.Tag'>
print(type(soup.title.string)) # 输出<class 'bs4.element.NavigableString'>

遍历文档树

  • contents 返回的是一个所有子节点的列表(了解)
  • children 返回的是一个子节点的迭代器(了解)
  • descendants 返回的是一个生成器遍历子子孙孙(了解)
  • string 获取标签里面的内容 .string 属性获取元素的文本。如果元素不存在文本,则返回 None 需要注意的是,如果元素包含了多个子元素,则该属性返回 None。(掌握)
  • strings 返回是一个生成器对象用过来获取多个标签内容(掌握)
  • stripped_strings 和strings 基本一致 但是它可以把多余的空格去掉(掌握)

搜索文档树

  1. find():返回搜索到的第一条数据
  2. find_all():以列表形式返回所有的搜索到的标签数据
  3. select(): 搜索方法 根据css定位器去定位

div=soup.find('div',attrs={'class':"resblock-desc-wrapper"}) # 找标签的第一种写法
div1=soup.find('div',class_="resblock-desc-wrapper") # 找标签的第二种写法
print(div.div.a.string) # 输出第一个a标签的文本内容

div_box1=soup.find_all('div',attrs={'class':'resblock-desc-wrapper'})
print(div_box1) # 输出的是一个生成器需要加for循环遍历
for i in div_box1:
    title=i.find('div','resblock-name').a.string # 输出第一个a标签的文本内容 
    address=''.join(i.find('div','resblock-location').stripped_strings) # 输出的内容是去掉空格符和换行符的内容
    
div_box2=soup.select('div.resblock-desc-wrapper') # 找的是div标签且属性为class  返回的是一个可迭代对象
print(len(div_box2))
for i in div_box2:
    title=i.div.a.string
    mianji=i.select('div.resblock-area > span')[0].string # 因为.select()返回的是一个列表,而列表不能直接取到文本
    address=''.join(i.select('div.resblock-location')[0].stripped_strings)
    price=''.join(i.select('div.main-price')[0].stripped_strings)
    print(title,mianji,address,price)

最后:创作不易麻烦小哥哥小姐姐高抬贵手点赞收藏加关注,感谢!