解析数据,除了前面的BeautifulSoup库,另有正则表达式和Xpath两种方法。
一、正则表达式
正则表达式(简称RE)是一种用来形貌和匹配字符串模式的工具。
它广泛应用于文本处置惩罚、数据验证、文本搜刮和更换等场景。正则表达式利用一种特殊的语法,可以对字符串进行复杂的模式匹配。
正则表达式测试:在线正则表达式测试
1、常用元字符
元字符:具有固定含义的特殊符号。每个元字符,默认只匹配一个字符串,而且不能匹配换行符。
元字符形貌示例.匹配除换行符以外的任意字符a.b 可以匹配 a1b、acb\w匹配字母、数字或下划线\w+ 匹配 hello、world_123\s匹配任意的空白字符\s+ 匹配空格、制表符等\d匹配数字\d+ 匹配 123、456\n匹配一个换行符hello\nworld 匹配换行符\t匹配一个制表符hello\tworld 匹配制表符^匹配字符串的开始^Hello 匹配 Hello 开头的字符串$匹配字符串的结束World$ 匹配 World 结尾的字符串\W匹配非字母、非数字、非下划线的字符\W+ 匹配 !@#、$%^\D匹配非数字字符\D+ 匹配 abc、XYZ\S匹配非空白字符\S+ 匹配 hello、world123`ab`匹配字符 a 或字符 b(...)捕捉括号内的表达式,表示一个组(abc) 捕捉 abc[...]匹配方括号中的任意字符[abc] 匹配 a、b 或 c[^...]匹配不在方括号中的任意字符[^abc] 匹配除 a、b、c 之外的任意字符 2、量词
量词:控制前面的元字符出现的次数
量词形貌*重复零次或更多次+重复一次或更多次?重复零次或一次{n}重复n次{n,}重复n次或更多次{n,m}重复n到m次 惰性匹配.*?:尽大概少地匹配字符。在重复元字符后加 ? 实现惰性匹配。
贪心匹配.*:尽大概多地匹配字符。默认的重复元字符都是贪心的。
3、Re模块
在Python中利用处置惩罚正则表达式,可以利用 re 模块,这个模块提供了一系列用于搜刮、匹配和操作字符串的函数。
函数形貌re.search(pattern, string, flags=0)搜刮字符串,返回第一个匹配的对象;若无匹配返回 Nonere.match(pattern, string, flags=0)从字符串起始位置匹配模式;若匹配乐成返回匹配对象,否则 Nonere.fullmatch(pattern, string, flags=0)整个字符串完全匹配模式返回匹配对象,否则返回 Nonere.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}")
复制代码
4、爬取豆瓣电影
从<li>标签开始,徐徐匹配到包含电影名的<span class="title">标签,利用非贪心模式(.*?)匹配中间大概存在的任意字符,直到找到下一个明白的标志,用命名捕捉组(?P<name>)提取出电影名部门。
Re表达式写法:
- <li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)</span>
复制代码 爬虫代码:
- import requestsimport refrom bs4 import BeautifulSoupheaders = { "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}")
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |