回忆往昔:
上一篇文章学习了怎么通过request获取到网页的源代码,以便于我们从中提取想要的信息。
这篇文章就是介绍如何从中提取自己想要的信息。主要有三种方式
1.正则表达式(re)
正则表达的的基础这里就不多介绍了,介绍一下常用的方法吧
1.1 re.findall('表达式','被查找的数据'):查到所有匹配到的数据以列表的方式输出
import re
#第一种 re.findall
res = re.findall(r"\d+","我叫拉拉骆驼,今年18岁,2000年")#在正则表达式前面加上
#r是常见的转意字符方式
print(res)
#结果为['18', '2000']
1.2 re.finditer('表达式','被查找的数据'):查到所有匹配到的数据以迭代器的方式输出,需要循环取出。这里容易忘记最后需要把value用group取出
res1 = re.finditer(r"\d+","我叫拉拉骆驼,今年18岁,2000年")#得到的结果是一个迭代器,需要取出来
print(res1)
for item in res1:
print(item)
print(item.group())#group是将value从中取出
"""输出结果为:
<callable_iterator object at 0x00000296E6A81E20>
<re.Match object; span=(8, 10), match='18'>
18
<re.Match object; span=(12, 16), match='2000'>
2000
"""
1.3 re.search('表达式','被查找的数据'):这个返回匹配到的第一个数据,并且是以对象的形式,需要用group取出value值
res2 = re.search(r"\d+","我叫卡卡骆驼,今年18岁,2000年")#匹配到第一个后停止匹配
print(type(res2))
print(res2)
print(res2.group())
输出结果为:
<class 're.Match'>
<re.Match object; span=(8, 10), match='18'>
18
1.4 re.match('表达式','被查找的数据'):此方法只会从头开始匹配,如果匹配到了则返回值,匹配不到返回none。
res3 = re.match(r"\d+","我叫卡卡,今年18岁,2000年")#从第一个开始匹配,第一个没有没有则直接为None
print(res3)
print(res3.group())
结果为
None
Traceback (most recent call last):
File "D:\DownloadProgram\PyCharm\PythonProject\pythonProject1\day02\gyd_re01.py", line 23, in <module>
print(res3.group())
AttributeError: 'NoneType' object has no attribute 'group'
空值不可以获取value
最后还有一个预加载:re.compile('表达式'):可以预加载,只加载一次,有效减少内存占用。
一般先试用compile,后面再接着四种匹配方法。
import re
com = re.compile(r"\d+")#预加载正则表达式,使其不重复
d = com.finditer("我叫拉拉骆驼,今年18岁,2000年")
for i in d :
print(i.group())
结果为
18
2000
还有两个重要的匹配:贪婪匹配和惰性匹配
贪婪匹配:.* (.是任意,*是重复0次或者多次,所以贪婪匹配就是尽可能匹配的多)
惰性匹配:.*? (?是重复0次或一次 , 所以惰性匹配是尽可能匹配的少)
让我们来试验一下
import re
s = "我是卡卡骆驼卡卡骆驼"
t = re.findall(r'我是.*骆驼',s)
print(t)
#结果为:['我是卡卡骆驼卡卡骆驼']
t2 = re.findall(r'我是.*?骆驼',s)
print(t2)
#结果为:['我是卡卡骆驼']
简单的总结一下:正则表达式有四种常用的方法,其中findall返回的是列表,其余三种都是需要用group取value,其中第二中方法效率最高,也最常用。
compile方法可以预加载表达式,加载一次可以用多次。
两个匹配常用的是.*?
2.bs4
bs4是基于标签获取数据的
使用流程为
2.1初始化:page = beautifulsoup(被查取的数据,"html.parser")
2.2 两个方法:
dive= page.find('标签名',id= '') 只能查找到第一个,相当于re.search
dive= page.findall('标签名',id= '') 查找多个
其中标签名class比较特殊,它是python中的保留关键字,需要用字典的形式进行装备
find:
from bs4 import BeautifulSoup
import requests
#获取到页面源码
url = 'https://beijing.qianlong.com/2023/1228/8173119.shtml'
resp = requests.get(url)
resp.encoding = "utf-8"
#初始化bs4
page = BeautifulSoup(resp.text, 'html.parser')
div = page.find("div", id="contentStr")#解析到div
f = open(file="新闻.txt", mode="w", encoding="utf-8")
ps = div.find_all("p")#找到文字
for p in ps:
p=p.text.strip()
print(p)
f.write(p)
f.close()#关闭
resp.close()#关闭
findall
import requests
from bs4 import BeautifulSoup
url = 'https://desk.3gbizhi.com'
#获取网页信息
response = requests.get(url)
page=response.text
#print(response.text)
#初始化bs4
soup = BeautifulSoup(page,'html.parser')
#需要注意的是,因为class是python的保留关键字,若要匹配标签内class的属性,需要特殊的方法:在attrs属性用字典的方式进行参数传递
#多个属性定位是也需要用字典的方式
a = soup.findAll('a',{'class':'desk imgw'})#class 需要用字典来装备#找到图片地址
n=1
for i in a:
href=i.get('href')
#print(href)
child_page = requests.get(href)#找到子页面中的下载地址
#print(child_page.text)
child_soup = BeautifulSoup(child_page.text,'html.parser')
child_soup_1 = child_soup.find("div",{'class':'img-table-cell wallphotos'})
img = child_soup_1.find("img")
img_url = img.get('src')
#print(img_url)
img = requests.get(img_url)#下载图片
#保存图片
with open(f'test{n}.jpg','wb') as f:#二进制需要用wb进行保存
f.write(img.content)#content:图片需要用二进制保存
print(f"第{n}个下载完成")
n+=1
2.3 获取数据
获取属性值:div.get('属性')
获取文本值: div.text
总结:bs4先初始化再通过两个方法找标签,找到标签后就取文本或者属性
3.xpath
xpath是通过节点获取数据
流程:
3.1初始化(变树):tree=etree.HTML(网页源码)
3.2查找节点:
tree.xpth(父/子/孙)
tree.xpth(父//孙)
tree.xpth(父/*/孙) *是整数
tree.xpth(父/子[@id = ''])属性控制
3.3获取值/属性值
获取文本值:tree.xpath(父/子/text())
获取属性值:tree.xpath(父/子/@id)
总结:xpath与bs4的流程极为相似,获取值的方式也比较相似,先初始化,在从节点中拿值。