【爬虫】解析爬取的数据


解析数据,除了前面的BeautifulSoup库,还有正则表达式和Xpath两种方法。

一、正则表达式

正则表达式(简称RE)是一种用来描述和匹配字符串模式的工具。

它广泛应用于文本处理、数据验证、文本搜索和替换等场景。正则表达式使用一种特殊的语法,可以对字符串进行复杂的模式匹配。

正则表达式测试:在线正则表达式测试

1、常用元字符

元字符:具有固定含义的特殊符号。每个元字符,默认只匹配一个字符串,并且不能匹配换行符。

元字符 描述 示例
. 匹配除换行符以外的任意字符 a.b 可以匹配 a1bacb
\w 匹配字母、数字或下划线 \w+ 匹配 helloworld_123
\s 匹配任意的空白字符 \s+ 匹配空格、制表符等
\d 匹配数字 \d+ 匹配 123456
\n 匹配一个换行符 hello\nworld 匹配换行符
\t 匹配一个制表符 hello\tworld 匹配制表符
^ 匹配字符串的开始 ^Hello 匹配 Hello 开头的字符串
$ 匹配字符串的结束 World$ 匹配 World 结尾的字符串
\W 匹配非字母、非数字、非下划线的字符 \W+ 匹配 !@#$%^
\D 匹配非数字字符 \D+ 匹配 abcXYZ
\S 匹配非空白字符 \S+ 匹配 helloworld123
`a b` 匹配字符 a 或字符 b
(...) 捕获括号内的表达式,表示一个组 (abc) 捕获 abc
[...] 匹配方括号中的任意字符 [abc] 匹配 abc
[^...] 匹配不在方括号中的任意字符 [^abc] 匹配除 abc 之外的任意字符

2、量词

量词:控制前面的元字符出现的次数

量词 描述
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

惰性匹配.*?:尽可能少地匹配字符。在重复元字符后加 ? 实现惰性匹配。
贪婪匹配.*:尽可能多地匹配字符。默认的重复元字符都是贪婪的。

惰性匹配

贪婪匹配

3、Re模块

在Python中使用处理正则表达式,可以使用 re 模块,这个模块提供了一系列用于搜索、匹配和操作字符串的函数。

函数 描述
re.search(pattern, string, flags=0) 搜索字符串,返回第一个匹配的对象;若无匹配返回 None
re.match(pattern, string, flags=0) 从字符串起始位置匹配模式;若匹配成功返回匹配对象,否则 None
re.fullmatch(pattern, string, flags=0) 整个字符串完全匹配模式返回匹配对象,否则返回 None
re.findall(pattern, string, flags=0) 返回字符串中所有非重叠匹配的列表
re.finditer(pattern, string, flags=0) 返回字符串中所有非重叠匹配的迭代器
re.sub(pattern, repl, string, count=0, flags=0) 用替换字符串替换匹配模式的所有部分,返回替换后的字符串
re.split(pattern, string, maxsplit=0, flags=0) 根据模式匹配分割字符串,返回分割后的列表
import re

# 示例文本
text = "在2024年,Python是最受欢迎的编程语言之一。Python 3.9版本在2020年发布。"

# 1. re.search() 搜索字符串,返回第一个匹配的对象
# 查找第一个数字序列
search_result = re.search(r'\d+', text)
if search_result:
    print(f"re.search: 找到的第一个数字是 '{search_result.group()}',位置在 {search_result.start()}")  

# 2. re.match() 从字符串起始位置匹配模式
# 匹配字符串开头是否为 '在'
match_result = re.match(r'在', text)
if match_result:
    print(f"re.match: 匹配的字符串是 '{match_result.group()}',位于字符串的开始")

# 3. re.fullmatch() 整个字符串完全匹配模式
# 检查整个字符串是否只包含中文字符
fullmatch_result = re.fullmatch(r'[\u4e00-\u9fff]+', '在编程')
if fullmatch_result:
    print(f"re.fullmatch: 整个字符串完全匹配,匹配到的内容是 '{fullmatch_result.group()}'")  

# 4. re.findall() 返回字符串中所有非重叠匹配的列表
# 查找所有的数字序列
findall_result = re.findall(r'\d+', text)
print(f"re.findall: 找到的所有数字序列是 {findall_result}") 

# 5. re.finditer() 返回字符串中所有非重叠匹配的迭代器
# 查找所有的数字序列,并逐一输出
finditer_result = re.finditer(r'\d+', text)
for match in finditer_result:
    print(f"re.finditer: 找到的数字是 '{match.group()}',位置在 {match.start()}")  

# 6. re.sub() 用替换字符串替换匹配模式的所有部分
# 将所有数字替换为 '#'
sub_result = re.sub(r'\d+', '#', text)
print(f"re.sub: 替换后的字符串是: {sub_result}") 

# 7. re.split() 根据模式匹配分割字符串
# 按照空白字符或标点分割字符串
split_result = re.split(r'[,。 ]+', text)
print(f"re.split: 分割后的字符串列表是: {split_result}") 

image-20240608195856954

4、爬取豆瓣电影

image-20240608200527961

<li>标签开始,逐步匹配到包含电影名的<span class="title">标签,使用非贪婪模式(.*?)匹配中间可能存在的任意字符,直到找到下一个明确的标记,用命名捕获组(?P<name>)提取出电影名部分。

Re表达式写法:

<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)</span>

爬虫代码:

import requests
import re
from bs4 import BeautifulSoup

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
}

for start_num in range(0, 250, 25):
    response = requests.get(f"https://movie.douban.com/top250?start={start_num}", headers=headers)
    # 拿到页面源代码
    html = response.text
    # 使用re解析数据
    obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)</span>',re.S)
    # 开始匹配
    result = obj.finditer(html)
    # 打印结果
    for it in result:
        print(it.group('name'))

二、Xpath

Xpath是在XML文档中搜索的一门语言,它可以通过路径表达式来选择节点或节点集,HTML是XML的一个子集。

安装lxml模块: pip install lxml

1、Xpath解析

Ⅰ、节点选择

符号 解释
/ 从根节点选择。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选择当前节点。
.. 选择当前节点的父节点。
@ 选择属性。

Ⅱ、路径表达式

表达式 解释
/bookstore/book 选择bookstore节点下的所有book子节点。
//book 选择文档中的所有book节点,不考虑它们的位置。
bookstore/book[1] 选择bookstore节点下的第一个book子节点。
//title[@lang] 选择所有具有lang属性的title节点。
//title[@lang='en'] 选择所有lang属性为’en’的title节点。

Ⅲ、常用函数

  • text(): 选择元素的文本。
  • @attr: 选择元素的属性。
  • contains(): 判断包含关系。
  • starts-with(): 判断开始部分。
from lxml import etree

html_content = '''
<html>
  <body>
    <div class="movie">
      <span class="title">肖申克的救赎</span>
      <span class="title">The Shawshank Redemption</span>
    </div>
    <div class="movie">
      <span class="title">霸王别姬</span>
      <span class="title">Farewell My Concubine</span>
    </div>
  </body>
</html>
'''

# 解析HTML
tree = etree.HTML(html_content)

# 提取电影标题
titles_cn = tree.xpath('//div[@class="movie"]/span[@class="title"][1]/text()')
titles_en = tree.xpath('//div[@class="movie"]/span[@class="title"][2]/text()')

# 打印结果
for cn, en in zip(titles_cn, titles_en):
    print(f'中文标题: {cn}, 英文标题: {en}')
//div[@class="movie"]/span[@class="title"][1]/text()

//div[@class="movie"]:选择所有class为movie的div元素。

/span[@class="title"][1]:选择每个div中class为title的第一个span元素。

/text():获取span元素的文本内容。

//div[@class="movie"]/span[@class="title"][2]/text()

类似上述表达式,但选择的是每个div中class为title的第二个span元素。

2、爬取豆瓣电影

豆瓣

import requests
from lxml import etree

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
}

for start_num in range(0, 250, 25):
    response = requests.get(f"https://movie.douban.com/top250?start={start_num}", headers=headers)
    # 拿到页面源代码
    html = response.text
    # 使用lxml解析页面
    html = etree.HTML(html)
    # 提取电影名字
    titles = html.xpath('//*[@id="content"]/div/div[1]/ol/li/div/div[2]/div[1]/a/span[1]/text()')
    # 提取评分
    ratings = html.xpath('//*[@id="content"]/div/div[1]/ol/li/div/div[2]/div[2]/div/span[2]/text()')
    # 打印结果
    for title, rating in zip(titles, ratings):
        print(f"电影: {title} 评分: {rating}")

相关推荐

  1. Python-数据爬虫

    2024-07-12 16:48:02       19 阅读
  2. Python-数据爬虫

    2024-07-12 16:48:02       21 阅读
  3. Pyhon爬虫之Ajax数据

    2024-07-12 16:48:02       39 阅读
  4. python网络爬虫需要数据

    2024-07-12 16:48:02       27 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 16:48:02       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 16:48:02       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 16:48:02       57 阅读
  4. Python语言-面向对象

    2024-07-12 16:48:02       68 阅读

热门阅读

  1. CHD安装

    2024-07-12 16:48:02       22 阅读
  2. 开源项目有哪些机遇和挑战?

    2024-07-12 16:48:02       21 阅读
  3. 敏捷项目管理与PMP有什么区别?彻底说明白!

    2024-07-12 16:48:02       26 阅读
  4. MySQL中客户端会话状态的服务器跟踪描述

    2024-07-12 16:48:02       22 阅读
  5. 创建型模式-工厂模式

    2024-07-12 16:48:02       19 阅读
  6. C++多线程读写文件

    2024-07-12 16:48:02       24 阅读
  7. 利用大数据分析股市异常资金

    2024-07-12 16:48:02       21 阅读
  8. PyTorch 2-深度学习-模块

    2024-07-12 16:48:02       21 阅读
  9. 科锐国际2024年OD招聘,技术岗急招

    2024-07-12 16:48:02       22 阅读
  10. 使用 CSS 实现渐变效果

    2024-07-12 16:48:02       25 阅读