正则表达式、xpath、BeautifulSoup和JSONPath的区别?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正则表达式、xpath、BeautifulSoup和JSONPath的区别?相关的知识,希望对你有一定的参考价值。

1.正则表达式是进行内容匹配,将符合要求的内容全部获取;xpath()能将字符串转化为标签,它会检测字符串内容是否为标签,但是不能检
测出内容是否为真的标签;Beautifulsoup是Python的一个第三方库,它的作用和 xpath 作用一样,都是用来解析html数据的相比之下,
xpath的速度会快一点,因为xpath底层是用c来实现的
2.三者语法不同,正则表达式使用元字符,将所有获得内容与匹配条件进行匹配,而xpath和bs4将获取的解析后的源码进行按条件筛选,筛选
出想要的标签即根据标签属性来找到指定的标签,之后对标签进行对应内容获取。
参考技术A

从处理内容角度和实现语言来说:

    正则表达式:

      处理内容:去查找或替换符合特定规则的字符串

      实现语言:不是一种语言,而是一种通用的技术,规范

        有很多编程语言和工具都支持

          比如

            Python的re

            VSCode中的查找和替换

            等等

    xpath:

      处理内容:匹配html/xml中的元素

      实现语言:不是一种语言,而是一种通用的技术,规范

        很多编程语言和工具都支持

          比如

            Python中的libxml2

            Chrome的开发者工具

            等等

    BeautifulSoup:

      处理内容:处理html或xml,查找/替换等操作

      实现语言:属于Python的一个处理html/xml的解析库

    JSONPath:

      处理内容:把(json格式的)字符串转换为json对象

      实现语言:属于Java的一个json库


我的相关教程,供参考:

    正则

应用广泛的超强搜索:正则表达式

正则表达式应用举例

Python中正则表达式:re模块详解


    XPath

XPath知识总结


吐槽:百度知道的编辑器,真心垃圾,连有序列表的缩进和插入链接都不能很好的支持。

关于爬虫解析数据的4种方式

目录

一、XPath解析数据

1、XPath解析数据

2、XML的树形结构

3、使用XPath选取节点

4、课堂案例 - 爬取起点小说网

二、BeautifulSoup解析数据

1、BeautifulSoup

2、BeautifulSoup的使用

3、使用BeautifulSoup爬取淘宝网首页

三、正则表达式

1、正则表达式

2、正则语法

3、特殊序列

4、正则处理函数

5、课堂案例(下载糗事百科小视频)

6、课外案例

四、pyquery解析数据

1、pyquery

2、pyquery的初始化方式

3、pyquery的使用

4、课堂案例(爬取起点小说网)


一、XPath解析数据

1、XPath解析数据

  • XPath
    • 全称:XML Path Language是一种小型的查询语言
    • 是一门在XML文档中查找信息的语言
  • XPath的优点
    • 可在XML中查找信息
    • 支持HTML的查找
    • 可通过元素和属性进行导航
  • XPath需要依赖lxml库
    • 安装方式: pip install lxml

2、XML的树形结构

3、使用XPath选取节点

序号

表达式

描述

1

nodename

选取此节点的所有子节点

2

/

从根节点选择

3

//

从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置

4

.

选取当前节点

5

..

选取当前节点的父节点

6

/text()

选取当前路径下的文本内容

7

/@xxx

提取当前路径下标签的属性值

8

|可选符

可选择若干个路径//p|//div,在当前路径下选取所有符合条件的p标签和div标签

序号

表达式

描述

1

xpath('./body/div[1]')

选取body下的第一个div节点

2

xpath('./body/div[ last() ]')

选取body下最后一个div节点

3

xpath('./body/div[ last()-1 ]')

选取body下倒数第二个div节点

4

xpath('./body/div[ position()<3 ]')

选取body下前两个div节点

5

xpath('./body/div[ @class ]')

选取body下带有class属性的div节点

6

xpath('./body/div[ @class="main" ]')

选取body下class属性为main的div节点

7

xpath('./body/div[ price>35.00 ]')

选取body下price元素大于35的div节点

4、课堂案例 - 爬取起点小说网

  • 下载谷歌浏览器XPath插件
  • 安装XPath插件
  • 使用XPath
import requests
from lxml import etree
url='https://www.qidian.com/rank/yuepiao'
headers='user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'

# 发送请求
resp=requests.get(url,headers)
e=etree.HTML(resp.text)     # 类型转换,把str类型转换成class 'lxml.etree._Element'
# print(type(e))        # <class 'lxml.etree._Element'>
names=e.xpath('//div[@class="book-mid-info"]/h4/a/text()')  # 获取小说名称
authors=e.xpath('//p[@class="author"]/a[1]/text()')         # 获取小说作者
# print(names)        # ['大奉打更人', '这个人仙太过正经', '从红月开始', '稳住别浪', 。。。]
# print(authors)      # ['卖报小郎君', '言归正传', '黑山老鬼', '跳舞', '我最白',  。。。]

for name,author in zip(names,authors):
    print(name, ":", author)
# 大奉打更人 : 卖报小郎君
# 这个人仙太过正经 : 言归正传
# 从红月开始 : 黑山老鬼
# 稳住别浪 : 跳舞
# ...    ...

二、BeautifulSoup解析数据

1、BeautifulSoup

  • BeautifulSoup
    • 是一个可以从HTML或XML文件中提取数据的Python库。其功能简单而强大、容错能力强、文档相对完善,清晰易懂
    • 非Python标准模块,需要安装才能使用
  • 安装方式
    • pip install bs4
  • 测试方式
    • import bs4
  • 解析器
    • BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果不安装第三方解析器,则Python会使用默认浏览器

序号

解析器

使用方法

优点

缺点

1

标准库

BeautifulSoup(html,'html.parser')

内置标准库,速度适中,文档容错能力强

Python3.2版本前的文档容错能力差

2

lxml HTML

BeautifulSoup(html, 'lxml')

速度快,文档容错能力强

安装C语言库

3

lxml XML

BeautifulSoup(html, 'xml')

速度快,唯一支持XML

安装C语言库

4

html5lib

BeautifulSoup(html, 'html5lib')

容错能力最强,可生成HTML5

运行慢,扩展差

from bs4 import BeautifulSoup

html='''
    <html>
       <head>
          <title>今天又是美好的一天</title>
        </head>
        <body>
            <h1 class="info bg" float="left">早起对自己说:我真美!</h1>
            <a href="http://www.baidu.com">百度</a>
            <h2><!--注释的内容--></h2>
        </body>
    </html>
'''
# bs=BeautifulSoup(html, 'html.parser')
bs=BeautifulSoup(html, 'lxml')
print(bs.title)     # 获取标题         <title>今天又是美好的一天</title>
print(bs.h1.attrs)    # 获取h1标签的所有属性   'class': ['info', 'bg'], 'float': 'left'

# 获取单个属性
print(bs.h1.get('class'))       # ['info', 'bg']
print(bs.h1['class'])           # ['info', 'bg']
print(bs.a['href'])             # http://www.baidu.com

# 获取文本内容
print(bs.title.text)            # 今天又是美好的一天
print(bs.title.string)          # 今天又是美好的一天

# 获取内容
print('-----', bs.h2.string)       # ----- 注释的内容
print('-----', bs.h2.text)         # -----
# string可以获取注释的内容,但是text不能获取注释内容

2、BeautifulSoup的使用

  • BeautifulSoup提取数据的常用方法

返回值类型

方法

功能

语法

举例

Tag

find()

提取满足要求的首个数据

bs.find(标签,属性)

bs.find('div', class_='books')

Tag

find_all()

提取满足要求的所有数据

bs.find_all(标签,属性)

bs.find_all('div', class_='books')

  • CSS选择题

功能

举例

通过ID查找

bs.select('#abc')

通过classa查找

bs.select('.abc')

通过属性查找

bs.select(a[' class="abc" '])

  • Tag对象

功能

举例

获取标签

bs.title

获取所有属性

bs.title.attrs

获取单个属性的值

bs.div.get('class')

bs.div['class']

bs.a['href']

from bs4 import BeautifulSoup

html='''
    <title>今天又是美好的一天</title>
    <div class="info" float="left">今天又是美好的一天</div>
   <div class="info" float="right" id="gb">
      <span>好好学习,天天向上</span>
      <a href="http://www.baidu.com">百度</a>
   </div>
   <span>人生苦短,唯有爱情</span>
'''

bs=BeautifulSoup(html, 'lxml')

print(bs.title, type(bs.title))      # 获取标题及其类型
# <title>今天又是美好的一天</title> <class 'bs4.element.Tag'>

print(bs.find('div',class_='info'), type(bs.find('div',class_='info')))     # 获取第一个满足条件的标签
# <div class="info" float="left">今天又是美好的一天</div> <class 'bs4.element.Tag'>

print(bs.find_all('div', class_='info'))    # 得到的是一个标签的列表
# [<div class="info" float="left">今天又是美好的一天</div>, <div class="info" float="right" id="gb">
# <span>好好学习,天天向上</span>
# <a href="http://www.baidu.com">百度</a>
# </div>]

for item in bs.find_all('div',class_='info'):
    print(item, type(item))

print(bs.find_all('div', attrs='float':'right'))  # 得到属性为'float':'right'的div标签

print('---------------CSS选择器---------------------')
print(bs.select("#gb"))
print(bs.select(".info"))

print(bs.select('div>span'))    # [<span>好好学习,天天向上</span>]
print(bs.select('div.info>span'))    # [<span>好好学习,天天向上</span>]

for item in bs.select('div.info>span'):
    print(item.text)    # 好好学习,天天向上

3、使用BeautifulSoup爬取淘宝网首页

import requests
from bs4 import BeautifulSoup
url='https://www.taobao.com/'
headers='user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
resp=requests.get(url,headers)
# print(resp.text)        # <html>... ...</html>
bs=BeautifulSoup(resp.text,'lxml')
a_list=bs.find_all('a')
# print(len(a_list))      # 128
for a in a_list:
    url=a.get('href')
    # print(url)
    if url==None:
        continue
    if url.startswith('http') or url.startswith('https'):
        print(url)

三、正则表达式

1、正则表达式

  • 是一个特殊的字符序列,它能帮助用户便捷地检查一个字符串是否与某种模式匹配
  • Python的正则模块是re,是Python的内置模块,不需要安装,导入即可

2、正则语法

序号

元字符

说明

1

.

匹配任意字符(不包括\\n)

2

^

匹配字符串的开头

3

$

匹配字符的末尾

4

*

匹配前一个元字符0到多次

5

+

匹配前一个元字符1到多次

6

?

匹配前一个元字符0到1次

7

m

匹配前一个字符m次

8

m,n

匹配前一个字符m到n次

9

m,n?

匹配前一个字符m到n次,并且取尽可能少的情况

10

\\\\

对特殊字符进行转义

11

[]

一个字符的集合,可匹配其中任意一个字符

12

|

逻辑表达式“或”,比如 a|b 代表可匹配a或者b

13

(...)

被括起来的表达式作为一个元组。findall()在有组的情况下只显示组的内容

3、特殊序列

序号

元字符

说明

1

\\A

只在字符串开头进行匹配

2

\\b

匹配位于开头或者结尾的空字符串

3

\\B

匹配不位于开头或者结尾的空字符串

4

\\d

匹配任意十进制数,相当于[0-9]

5

\\D

匹配任意非数字字符,相当于[^0-9]

6

\\s

匹配任意空白字符,相当于[\\t\\n\\r\\f\\v]

7

\\S

匹配任意非空白字符,相当于[^\\t\\n\\r\\f\\v]

8

\\w

匹配任意数字、字母、下划线,相当于[a-zA-Z0-9_]

9

\\W

匹配任意非数字、字母、下划线,相当于[^a-zA-Z0-9_]

10

\\Z

只在字符串结尾进行匹配

11

[\\u4e00-\\u9fa5]

中文

4、正则处理函数

序号

正则处理函数

说明

1

re.match(pattern, string, flags=0)

尝试从字符串的开始位置匹配一个模式,如果匹配成功,就返回一个匹配成功的对象,否则返回None

2

re.search(pattern, string, flags=0)

扫描整个字符串并返回第一次成功匹配的对象,如果匹配失败,就返回None

3

re.findall(pattern, string, flags=0)

获取字符串中所有匹配的字符串,并以列表的形式返回

4

re.sub(pattern, repl, string, count=0,flags=0)

用于替换字符串中的匹配项,如果没有匹配的项则返回没有匹配的字符串

5

re.compile(pattern[ ,flags ])

用于编译正则表达式,生成一个正则表达式(Pattern)对象,供match()和search()函数使用

import re
s = 'I study Python3.8 every day'
print('--------match方法,从起始位置开始匹配--------')
print(re.match("I", s).group())     # I
print(re.match('\\w', s).group())    # I
print(re.match('.', s).group())     # I

print('--------search方法,从任意位置开始匹配,匹配第一个--------')
print(re.search('study', s).group())    # study
print(re.search('s\\w', s).group())      # st

print('--------findall方法,从任意位置开始匹配,匹配多个--------')
print(re.findall("y", s))           # 结果为数组   ['y', 'y', 'y', 'y']
print(re.findall("Python", s))      # ['Python']
print(re.findall("P\\w+.\\d", s))     # ['Python3.8']
print(re.findall("P.+\\d", s))     # ['Python3.8']

print('--------sub方法的使用,替换功能--------')
print(re.sub('study', 'like', s))     # 将study替换成like   I like Python3.8 every day
print(re.sub('s\\w+', 'like', s))     #  I like Python3.8 every day

5、课堂案例(下载糗事百科小视频)

爬取数据时,一定要记得先找F12代码,看看和爬取的数据是否一致,若一致,则可直接提取。

import re
import requests

url='http://www.qiushibaike.com/video/'
headers='user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
resp=requests.get(url,headers=headers)
# print(resp.text)

# 先随便找一个视频,看是否能提取到。单引号中的单引号用\\转义:\\'...\\'
# info=re.findall('<source src="//qiubai-video.qiushibaike.com/1EXAHVPHKWXFJYR2_org.mp4" type=\\'video/mp4\\' />', resp.text)
# print(info)     # ['<source src="//qiubai-video.qiushibaike.com/1EXAHVPHKWXFJYR2_org.mp4" type=\\'video/mp4\\' />']

info=re.findall('<source src="(.*)" type=\\'video/mp4\\' />', resp.text)
# print(info)     # 给出所有URL的相对位置的数组
lst=[]
for item in info:
    lst.append("https:"+item)
# print(lst)

# 循环
count=0
for item in lst:
    count+=1
    resp=requests.get(item, headers=headers)
    # 转成二进制存储
    with open('video/'+str(count)+'.mp4', 'wb') as file:
        file.write(resp.content)
print('视频下载完毕')

6、课外案例

用正则表达式提取51job网页中的信息

import requests
import re
from pandas import DataFrame
 
# 网址
url = "https://search.51job.com/list/000000,000000,0000,32,9,99,Java%25E5%25BC%2580%25E5%258F%2591,2,1.html"
# 获得网页对象
res = requests.get(url)
# 设置编码格式
res.encoding = "gbk"
 
# 职位名
# 将要提取的用(.*)表示,每条数据不同的地方用.*表示
position_pat = '<a target="_blank" title="(.*)" href=".*" onmousedown=".*">'  
position = re.findall(position_pat, res.text)
 
# 公司名
company_pat = '<span class="t2"><a target="_blank" title="(.*)" href=".*">.*</a></span>'
company = re.findall(company_pat, res.text)
 
# 工作地点
place_pat = '<div class="el">.*?<span class="t3">(.*?)</span>'  # 非贪婪模式
place = re.findall(place_pat, res.text, re.S)
 
# 薪资
salary_pat = '<div class="el">.*?<span class="t4">(.*?)</span>'  # 非贪婪模式
salary = re.findall(salary_pat, res.text, re.S)
 
# 将取出的信息放到数据框
jobInfo = DataFrame([position, company, place, salary]).T
# 设置列名
jobInfo.columns = ['职位名', '公司名', '工作地点', '薪资']
print(jobInfo.head())
 
# 将数据保存到本地
jobInfo.to_csv('51job2.csv')

四、pyquery解析数据

1、pyquery

  • pyquery库是jQuery的Python实现,就能以jQuery的语法来操作解析HTML文档,易用性和解析速度都很好
  • 前提条件:
    • 你对CSS选择器与jQuery有所了解
  • 非Python标准模块,需要安装
    • 安装方式
      • pip install pyquery
    • 测试方式
      • import pyquery

2、pyquery的初始化方式

  • 字符串方式

  • url方式

  • 文件

# 字符串方式
from pyquery import PyQuery as py
html='''
    <html>
       <head>
          <title>PyQuery</title>
       </head>
       <body>
          <h1>PyQuery</h1>
       </body>
    </html>
'''

doc=py(html)    # 创建PyQuery的对象,实际上就是在进行一个类型转换,将str类型转成PyQuery类型
print(doc)              # 和html一样的内容
print(type(doc))        # <class 'pyquery.pyquery.PyQuery'>
print(type(html))       # <class 'str'>
print(doc('title'))     # <title>PyQuery</title>
# url方式
from pyquery import PyQuery
doc=PyQuery(url='http://www.baidu.com', encoding='utf-8')
print(doc)              # 获取html
print(doc('title'))     # <title>百度一下,你就知道</title>
# 文件
from pyquery import PyQuery
doc=PyQuery(filename='a1.html')
print(doc)           # 获取html
print(doc('h1'))     # <h1>PyQuery</h1>

3、pyquery的使用

序号

提取数据

举例

1

获取当前节点

doc('#main')

2

获取子节点

doc('#main').children()

3

获取父节点

doc('#main').parent()

4

获取兄弟节点

doc('#main').siblings()

5

获取属性

doc('#main').attr('href')

6

获取内容

doc('#main').html() doc('#main').text()

from pyquery import PyQuery
html='''
    <html>
        <head>
            <title>PyQuery</title>
        </head>
        <body>
            <div id="main">
                <a href="http://www.baidu.com">百度</a>
                <h1>百度一下</h1>
            </div>
            <h2>Python学习</h2>
        </body>
    </html>
'''
doc=PyQuery(html)
# 获取当前节点
print(doc("#main"))      # 获取整个div
# 获取父节点
print(doc("#main").parent())      # 获取整个body
# 获取子节点
print(doc("#main").children())    # 获取<a>和<h1>
# # 获取兄弟节点
print(doc("#main").siblings())      # 获取<h2>

print('----------获取属性------------')
print(doc('a').attr('href'))     # http://www.baidu.com

print('----------获取标签的内容------------')
print(doc("#main").html())        #  获取<a>和<h1>,div中的所有都获取到了
print(doc("#main").text())          #  百度  百度一下, 只获取了div中的文本

4、课堂案例(爬取起点小说网)

import requests
from pyquery import PyQuery

url='https://www.qidian.com/rank/yuepiao'
headers='user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
resp=requests.get(url,headers)
# print(resp.text)

# 初始化PyQuery对象
doc=PyQuery(resp.text)      # 使用字符串初始化方式初始化PyQuery对象
# a_tag=doc('h4 a')       # 获取h4的a标签
# print(a_tag)
names=[a.text for a in doc('h4 a')]
# print(names)        # ['大奉打更人', '这个人仙太过正经', '从红月开始', '稳住别浪',....]

authors = doc('p.author a')       # 找<p class="author">下的<a>标签
# print(authors)

authors_lst=[]
for index in range(len(authors)):
    if index%2==0:
        authors_lst.append(authors[index].text)
# print(authors_lst)      # ['卖报小郎君', '言归正传', '黑山老鬼', '跳舞', '我最白', '白驹易逝', ...]

for name,author in zip(names,authors_lst):
    print(name, ':', author)
# 大奉打更人 : 卖报小郎君
# 这个人仙太过正经 : 言归正传
# 从红月开始 : 黑山老鬼
# 稳住别浪 : 跳舞
# ... ...

以上是关于正则表达式、xpath、BeautifulSoup和JSONPath的区别?的主要内容,如果未能解决你的问题,请参考以下文章

Python lxml包下面的xpath基本用法

数据的查找和提取[2]——xpath解析库的使用

如何将此 XPath 表达式转换为 BeautifulSoup?

python系列之BeautifulSoup的用法

Python中xPath技术和BeautifulSoup的使用

Python中xPath技术和BeautifulSoup的使用