python爬虫2-HTML文本处理

HTML文本处理

re模式匹配

正则表达式是一种强大的字符串匹配和处理工具,允许通过指定的模式来查找、替换和验证字符串。

函数

编译正则表达式

  • re.compile(pattern, flags=0): 将字符串形式的正则表达式编译为一个正则对象,用于后续的匹配操作。

匹配操作

  • re.match(pattern, string, flags=0): 从字符串的起始位置匹配模式。
  • re.search(pattern, string, flags=0): 扫描整个字符串,并返回第一个成功的匹配。
  • re.findall(pattern, string, flags=0): 返回字符串中所有与模式匹配的子串列表。
  • re.finditer(pattern, string, flags=0): 返回一个迭代器,每次迭代返回一个匹配对象。
  • re.fullmatch(pattern, string, flags=0): 如果整个字符串与模式匹配,则返回一个匹配对象,否则返回None。

替换操作

  • re.sub(pattern, repl, string, count=0, flags=0): 将字符串中与模式匹配的部分替换为指定的字符串。
  • re.subn(pattern, repl, string, count=0, flags=0): 类似于sub,但返回一个元组 (new_string, number_of_subs_made)

分割操作

  • re.split(pattern, string, maxsplit=0, flags=0): 根据模式分割字符串,返回分割后的子串列表。

正则表达式修饰符

  • re.IGNORECASE (或 re.I): 忽略大小写匹配。
  • re.MULTILINE (或 re.M): 多行匹配。
  • re.DOTALL (或 re.S): 让 . 匹配包括换行符在内的所有字符。
  • re.VERBOSE (或 re.X): 可以使用空格和注释来组织正则表达式。

示例

下面是一个简单的示例,展示如何使用正则表达式模块进行匹配和替换操作:

import re

# 示例文本
text = 'Hello, my email is john.doe@example.com. Please contact me.'

# 定义匹配邮箱地址的正则表达式模式,使用命名组
pattern = r'(?P<username>[\w\.-]+)@(?P<domain>[a-zA-Z\d\.-]+)\.(?P<tld>[a-zA-Z]{2,})'
emails = re.findall(pattern, text)
print(emails)
# [('john.doe', 'example', 'com')]


# 替换的新域名
new_domain = 'qq.com'

# 使用 re.sub() 替换匹配的邮箱地址,并保留原用户名和顶级域名
new_text = re.sub(pattern, fr'\g<username>@{new_domain}', text)

print(new_text)
# Hello, my email is john.doe@qq.com. Please contact me.

(?P<username>[\w\.-]+): 命名组 <username>,匹配一个或多个字母、数字、下划线、点号或破折号,用于表示电子邮件地址中的用户名部分。

@: 匹配电子邮件地址中的 @ 符号。

(?P<domain>[a-zA-Z\d\.-]+): 命名组 <domain>,匹配一个或多个字母、数字、破折号或点号,用于表示电子邮件地址中的域名部分。

\.(?P<tld>[a-zA-Z]{2,}): 匹配顶级域名(TLD),用于表示电子邮件地址中的顶级域名部分。

fr'\g<username>@{new_domain}': 在 re.sub() 中使用 \g<username> 来引用命名组 <username> 的内容,然后在替换字符串中使用 {new_domain} 替换原来的域名部分。

豆瓣数据

  1. 获取网页并保存
import requests

url = 'https://movie.douban.com/top250'
header = {
    'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}

reponse = requests.get(url,headers=header)
reponse.encoding = "utf-8"
with open('douban.html', 'w', encoding='utf-8') as fp:
    fp.write(reponse.text)
  1. 正则匹配,并保存为csv文件
import re
import csv
# 打开并读取文件
with open('douban.html', 'r', encoding='utf-8') as file:
    content = file.read()

# 匹配模式
obj = re.compile(r'<span class="title">(?P<name>.*?)</span>.*?<p class="">.*?<br>.*?'
                 r'(?P<year>\d+)&nbsp;.*?<span class="rating_num" property="v:average">(?P<rating>.*?)</span>',re.S)


# 使用 re.findall() 找到所有匹配的信息
result = obj.finditer(content)


# 保存找到的信息到CSV文件
with open('douban.csv', 'w', newline='', encoding='utf-8') as csvfile:
    csvwriter = csv.writer(csvfile)
    for it in result:
        dic = it.groupdict()
        csvwriter.writerow(dic.values())

# 使用 re.findall() 找到所有匹配的信息
result = obj.finditer(content)

# 匹配到的信息
for it in result:
    print(it.group("name"))
    print(it.group("year"))
    print(it.group("rating"))

bs4

Beautiful Soup(简称 bs4)是一个用于解析 HTML 和 XML 文件的 Python 库。它能够方便地从网页中提取数据,特别是结合其他库如 requests 进行网页抓取时。

find_all函数

find_all 方法用于查找文档中所有符合条件的元素。它返回一个包含所有匹配元素的列表。

语法

soup.find_all(name, attrs, recursive, string, limit, **kwargs)
  • name: 标签名,字符串类型或列表类型。如 'a'['a', 'b']
  • attrs: 属性,字典类型。如 {'class': 'link'}
  • recursive: 布尔类型,默认值为 True,表示是否递归查找子标签。
  • string: 用于查找包含特定字符串的标签。
  • limit: 整数类型,限制返回的结果数量。
  • **kwargs: 其他属性,直接作为关键字参数传入。

示例

from bs4 import BeautifulSoup

html_content = '''
<!DOCTYPE html>
<html>
<head>
    <title>Sample Page</title>
</head>
<body>
    <h1>Welcome to the Sample Page</h1>
    <p class="description">This is a simple HTML file for demonstration purposes.</p>
    <div class="content">
        <p>Here is some sample content.</p>
        <a href="https://www.example.com">Example Link</a>
        <a href="https://www.anotherexample.com">Another Example Link</a>
    </div>
</body>
</html>
'''

# 传入文本并解析为html
soup = BeautifulSoup(html_content, 'html.parser')

# 找到所有 <a> 标签
links = soup.find_all('a')
for link in links:
    print('链接文本:', link.text)
    print('URL:', link['href'])

# 运行结果
'''
链接文本: Example Link
URL: https://www.example.com
链接文本: Another Example Link
URL: https://www.anotherexample.com
'''

find函数

find 方法用于查找文档中第一个符合条件的元素。它返回单个元素。

语法

soup.find(name, attrs, recursive, string, **kwargs)
  • name: 标签名,字符串类型或列表类型。如 'a'['a', 'b']
  • attrs: 属性,字典类型。如 {'class': 'link'}
  • recursive: 布尔类型,默认值为 True,表示是否递归查找子标签。
  • string: 用于查找包含特定字符串的标签。
  • **kwargs: 其他属性,直接作为关键字参数传入。

示例

from bs4 import BeautifulSoup

html_content = '''
<!DOCTYPE html>
<html>
<head>
    <title>Sample Page</title>
</head>
<body>
    <h1>Welcome to the Sample Page</h1>
    <p class="description">This is a simple HTML file for demonstration purposes.</p>
    <div class="content">
        <p>Here is some sample content.</p>
        <a href="https://www.example.com">Example Link</a>
        <a href="https://www.anotherexample.com">Another Example Link</a>
    </div>
</body>
</html>
'''

# 传入文本并解析为html
soup = BeautifulSoup(html_content, 'html.parser')

# 找到第一个 <a> 标签
first_link = soup.find('a')
if first_link:
    print('第一个链接文本:', first_link.text)
    print('URL:', first_link['href'])

# 运行结果
'''
第一个链接文本: Example Link
URL: https://www.example.com
'''

豆瓣数据

获取网页并保存

import requests

url = 'https://movie.douban.com/top250'
header = {
    'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}

reponse = requests.get(url,headers=header)
reponse.encoding = "utf-8"
with open('douban.html', 'w', encoding='utf-8') as fp:
    fp.write(reponse.text)

bs4处理,并保存为csv文件

from bs4 import BeautifulSoup
import re
import csv

with open('douban.html', 'r', encoding='utf-8') as file:
    html_content = file.read()

# 解析 HTML 内容
soup = BeautifulSoup(html_content, 'html.parser')

# 标题
ol_grid_view = soup.find('ol', class_="grid_view")
span_title = ol_grid_view.find_all('span',class_="title")

# 过滤英文
name = []
for title in span_title:
    if '/' not in title.text:
        name.append(title.text)


# 年份
year = []
div_bd = ol_grid_view.find_all('div',class_="bd")
ps = []
for div in div_bd:
    ps.append(div.find_all('p',class_="")[0])

for p in ps:
    pattern = r'\b\d{4}\b'
    matches = re.findall(pattern, p.text)
    year.append(matches[0])

# 评分
rating = []
span_rating = ol_grid_view.find_all('span',class_="rating_num")
for rat in span_rating:
    rating.append(rat.text)


# 保存找到的信息到CSV文件
with open('douban2.csv', 'w', newline='', encoding='utf-8') as csvfile:
    csvwriter = csv.writer(csvfile)
    # 使用 zip 将三个列表合并成一个字典
    dic =  zip(name, year, rating)
    for v1, v2, v3 in dic:
        csvwriter.writerow([v1, v2, v3])

xpath

lxml 是一个强大的 Python 库,用于处理 XML 和 HTML 数据

基本路径表达式

以下是一些基本的 XPath 路径表达式示例:

  • 选取节点:
    • /: 根节点
    • //: 从当前节点选择所有后代节点
    • .: 当前节点
    • ..: 父节点
  • 选取具体节点:
    • /bookstore/book: 选取根元素 bookstore 下的所有 book 元素
    • //title: 选取所有 title 元素
    • //book[@category='cooking']: 选取所有 category 属性为 cooking 的 book 元素
  • 选取节点的内容:
    • /bookstore/book/title/text(): 选取根元素 bookstore 下的所有 book 元素的 title 子元素的文本内容

路径获取

通过浏览器右键可以方便获取xpath路径

image-20240702201705799

实例

from lxml import etree

# XML 文档字符串
xml_string = '''
<bookstore>
    <book category="cooking">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
    </book>
    <book category="children">
        <title lang="en">Harry Potter</title>
        <author>J.K. Rowling</author>
        <year>2005</year>
    </book>
</bookstore>
'''

# 解析 XML 字符串
root = etree.fromstring(xml_string)

# 使用 XPath 选取所有 title 元素的文本内容
titles = root.xpath('//title/text()')

# 打印所有 title 的文本内容
for title in titles:
    print("书名:", title)

# 使用 XPath 选取category=cooking的作者名
authors = root.xpath("/bookstore/book[@category='cooking']/author/text()")

# 打印作者名字
for author in authors:
    print("作者:",author)

豆瓣数据

获取网页并保存

import requests

url = 'https://movie.douban.com/top250'
header = {
    'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}

reponse = requests.get(url,headers=header)
reponse.encoding = "utf-8"
with open('douban.html', 'w', encoding='utf-8') as fp:
    fp.write(reponse.text)

lxml处理,并保存为csv文件

from lxml import etree
import re
import csv

# 打开并读取文件
with open('douban.html', 'r', encoding='utf-8') as file:
    content = file.read()

# 解析 XML 字符串
root = etree.HTML(content)

# 使用 XPath 选取所有 title 元素的文本内容
lis = root.xpath('//*[@id="content"]/div/div[1]/ol/li')

# 打开csv文件
csvfile = open('douban3.csv', 'w', newline='', encoding='utf-8')
csvwriter = csv.writer(csvfile)

    
for li in lis:
    name = li.xpath("./div/div[2]/div[1]/a/span[1]/text()")[0]		#名字
    year = li.xpath("./div/div[2]/div[2]/p[1]/text()[2]")[0]		#年份
    rating = li.xpath("./div/div[2]/div[2]/div/span[2]/text()")[0]	#评分
    year = re.findall(r'\b\d{4}\b', year)[0]	#对年份进行处理
	
    # 写入csv文件
    csvwriter.writerow([name, year, rating])

# 关闭csv文件
csvfile.close()
posted @ 2024-07-04 17:40  noahze  阅读(4)  评论(0编辑  收藏  举报