【自用】Python爬虫学习(二):网页解析的三种方式(re、bs4、xpath)


网页解析的三种方式

1.正则表达式-re解析

常用表达:

正则表达式常用字符:
===============常用元字符:===============
.       匹配除换行符以外的任意字符
\w      匹配字母或数字或下划线
\s      匹配任意的空白符
\d      匹配数字
\n      匹配一个换行符
\t      匹配一个制表符

^       匹配字符串的开始
$       匹配字符串的结尾

\W      匹配非字母或数字或下划线
\D      匹配非数字
\S      匹配非空白符

a|b     匹配字符a或字符b
()      匹配括号内的表达式,也表示一个组
[...]   匹配字符组中的字符
[^...]  匹配除了字符组中字符的所有字符

===============量词:控制前面的元字符出现的次数===============
*       重复零次或更多次
+       重复一次或更多次
?       重复零次或一次
{n}     重复n次
{n,}    重复n次或更多次
{n,m}   重复n到m次

===============贪婪匹配和情性匹配===============
.*      贪婪匹配
.*?     情性匹配

re常用函数:

import re

# re.findall(正则表达式,字符串),:匹配字符串中所有的符合正则的内容,返回的结果是一个列表
print("===============findall():===============")
lis = re.findall(r'\d+', '我的电话号码是10086,小明的电话是10010')
print(lis)
# ['10086', '10010']

# finditer():匹配字符串中所有的内容【返回的是选代器】,从迭代器中拿到内容需要:group(),效率更高
print("===============finditer():===============")
it = re.finditer(r'\d+', "我的电话号是:10086,小明的电话是:10010")
for i in it:
    print(i.group())
# 10086
# 10010

# search()找到一个结果就返回,返回的是match对象,拿数据需要.group()
print("===============search():===============")
s = re.search(r'\d+', "我的电话号是:10086,小明的电话是:10010")
print(s.group())
# 10086

# match是从头开始匹配
print("===============match():===============")
m = re.match(r'\d+', "10086,小明的电话是:10010")
print(m.group())
# 10086

# 预加载正则表达式
print("===============预加载正则表达式:===============")
obj = re.compile(r"\d+")
ret = obj.finditer("我的电话号是:10085,小明的电话是:10000")
for it in ret:
    print(it.group())
# 10085
# 10000

在html中的运用:

import re

text = """
<div class='jay'><span id='1′>郭某某</span></div>
<div class='jj'><span id='2′>宋某某</span></div>
<div class='jolin'><span id='3′>李某某</span></div>
<div class='sylar'><span id='4′>范某某</span></div>
<div class='tory'><span id='5′>刘某某</span></div>

"""
# (?P<分组名字>正则)可以单独从正则匹配的内容中进一步提取内容,re.S的作用是让.能匹配换行符
obj = re.compile(r"<div class='.*?><span id='(?P<num>\d+)′>(?P<name>.*?)</span></div>", re.S)

result = obj.finditer(text)
for it in result:
    print(it.group())
    # <div class ='jay' > < span id='1′>郭某某</span></div>
    print(it.group('name'))
    # 郭某某
    print(it.group('num'))
    # 1

2.BeautifulSoup解析

常用语法:

"""
-如何实例化BeautifulSoup对象:
	-from bs4 import BeautifulSoup
	-对象的实例化:
		-1.将本地的htmL文档中的数据加载到该对象中
			fp=open('./test.html','r',encoding='utf-8')
			soup=BeautifulSoup(fp,'lxml')
		2.将互联所网上获取的页面源码加载到该对象中
			page_text=response.text
			soup=BeautifulSoup(page_text,'lxml')
	-提供的用于数据解析的方法和属性:
		-soup.tagName:返回的是文档中第一次出现的tagName对应的标签
		-soup.find():
			-find('tagName'):等同于soup.div
		-属性定位
			-soup.find('div',class_/id/attr='song')
		-soup.find_all('tagName'):返回符合要求的所有标签(列表)
	-select:
		-select('某种选择器(id,class,标签……选择器)'),返回的是一个列表。
		-层级选择器:
			-soup.select('.tang>ul>li>a'):>表示的是一个层级
			-soup.select('.tang>ul a'):空格表示的多个层级
	-获取标签之间的文本数据:
		-soup.a.text/string/get_text()
		-text/get_text():可以获取某一个标签中所有的文本内容
		-string:只可以获取该标签下面直系的文本内容·
	-获取标签中属性值:
		-soup.a['href']

"""

用法举例:

import requests
from bs4 import BeautifulSoup

url = ''
hearders = {
    'User-Agent': ''
}
resp = requests.get(url=url, headers=hearders)
# 对象的实例化
soup = BeautifulSoup(resp.text, 'lxml')
# 标签定位
# 返回的是文档中第一次出现的tagName对应的标签
div_first1 = soup.find('div')
div_first2 = soup.div
# div_first1与div_first2效果一样

# 属性定位
# 写法1,添加下划线'class_'规避关键字class
soup.find('div', class_='song')
# 写法2,写成字典形式
soup.find('div', attrs={"class": "song"})

# 返回符合要求的所有标签(列表)
soup.find_all('tagName')

# 层级选择器,返回的是一个列表
# >表示的是一个层级
soup.select('.tang > ul > li > a')
# 空格表示的多个层级
soup.select('.tang > ul a')

# 获取标签之间的文本数据
"""
……
<div>
    <p>段落</p>
    内容测试
    <a href='www.baidu.com'>百度</a>
    <a href='www.bing.com'>必应</a>
</div>
……
"""
# 可以获取某一个标签中所有的文本内容
div_text1 = soup.div.text  # 结果包含:段落 内容测试 百度 必应
div_text2 = soup.div.get_text()  # 结果包含:段落 内容测试 百度 必应

# 只可以获取该标签下面直系的文本内容
# <a href='wwww.baidu.com'>百度</a>
a_text3 = soup.a.string  # 百度

# 获取标签中属性值:
# 获取<a href='wwww.baidu.com'>百度</a>中的href链接文本
# 方法1
web_links = soup.a['href']  # wwww.baidu.com
# 方法2
web_page = BeautifulSoup(resp.text, "html.parser")
div_list = web_page.find('div', class_='big-pic')
image_src = div_list.find('img').get('src')  # 用get拿到标签的对应属性

3.xpath解析

示例代码1:

from lxml import etree

xml = """
<book>
    <id>1</id>
    <name>野花遍地香</name>
    <price>1.23</price>
    <nick>臭豆腐</nick>
    <author>
        <nick id="10086">周大强</nick>
        <nick id="10010">周芷若</nick>
        <nick class="joy">周杰伦</nick>
        <nick class="jolin">蔡依林</nick>
        <div>
            <nick>惹了1</nick>
        </div>
        <span>
            <nick>惹了2</nick>
            <div>
                <nick>惹了3</nick>
            </div>
        </span>
    </author>
    
    <partner>
        <nick id="ppc">胖胖陈</nick>
        <nick id="ppbc">胖胖不陈</nick>
    </partner>
    
</book>

"""

tree = etree.XML(xml)
# result = tree.xpath("/book")
result = tree.xpath("/book/name/text()")  # ['野花遍地香']
# -/text()取的是标签中直系的文本内容;//text()标签中非直系的文本内容(所有的文本内容)

result = tree.xpath("/book/author/nick/text()")
# ['周大强', '周芷若', '周杰伦', '蔡依林']
result = tree.xpath("/book/author/div/nick/text()")
# ['惹了1']
result = tree.xpath("/book/author//nick/text()")
# ['周大强', '周芷若', '周杰伦', '蔡依林', '惹了1', '惹了2', '惹了3']
result = tree.xpath("/book/author/*/nick/text()")
# *任意的节点,通配符,['惹了1', '惹了2']

result = tree.xpath("/book//nick/text()")
# ['臭豆腐', '周大强', '周芷若', '周杰伦', '蔡依林', '惹了1', '惹了2', '惹了3', '胖胖陈', '胖胖不陈']

print(result)

示例代码2:

"Test.html"文件内容如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Title</title>
</head>
<body>
<ul>
    <li><a href="http://www.baidu.com">百度</a></li>
    <li><a href="http://www.google.com">谷歌</a></li>
    <li><a href="http://www.sogou.com">搜狗</a></li>
</ul>
<ol>
    <li><a href="feiji">飞机</a></li>
    <li><a href="dapao">大炮</a></li>
    <li><a href="huoche">火车</a></li>
</ol>

<div class="job">李嘉诚</div>
<div class="common">胡辣汤</div>

</body>
</html>
from lxml import etree

# 读取Test.html文件
tree = etree.parse("Test.html")
result = tree.xpath('/html')

result1 = tree.xpath("/html/body/ul/li/a/text()")
# ['百度', '谷歌', '搜狗']
print(result1)

# 注意这里的xpath的索引是从1开始的,li[1]代表取第一个,[]中数字代表索引
result2 = tree.xpath("/html/body/ul/li[1]/a/text()")
# ['百度']
print(result2)

result3 = tree.xpath("/html/body/ol/li/a[@href='dapao']/text()")
# ['大炮']
print(result3)

ol_li_list = tree.xpath("/html/body/ol/li")

for li in ol_li_list:
    # 从每一个1i中提取到文字信息
    result = li.xpath("./a/text()")  # 在li中继续去寻找,相对查找,注意用./
    print(result)
    # 拿到属性值:@属性值
    result2 = li.xpath("./a/@href")  # 在li中继续去寻找,获取到属性href的值
    print(result2)

print(tree.xpath("/html/body/ul/li/a/@href"))
# ['http://www.baidu.com', 'http://www.google.com', 'http://www.sogou.com']

print(tree.xpath("/html/body/div/text()"))
# ['李嘉诚', '胡辣汤']
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lucky_云佳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值