BeautifulSoup
数据解析原理:
1.标签定位
2.提取标签、标签属性中存储的数据
from bs4 import BeautifulSoup
import lxml
1.将本地的html文件中的数据加载
fp=open(filename,'r',encoding='utf-8')
res=BeautifulSoup(fp,'lxml') #返回BeautifulSoup对象
2.将互联网上获取的页面源码加载
page_text=response.text
res=BeautifulSoup(page_text,'lxml')
BS对象的一些方法属性
节点选择器: res.tagName 核心就是先选择节点得到Tag类型的数据,然后调用一系列属性提取信息。
url = 'https://www.baidu.com/'
r = requests.get(url, headers=header)
res = BeautifulSoup(r.text, 'lxml')
print(res.p) # res.tagName 返回html中第一个tagName标签 tagName可以是(div,a,b,li,p等任意标签),是tag类型数据
#print(res.p.string) # res.tagName 是一个tag类型的数据,可以调用其string属性来获取tagName节点内的文本。
#print(res.p.attrs) # 可以用tag类的 attrs属性来获取节点的所有属性(class,href,id等等),返回一个由属性名和属性值构成的字典。
#print(res.p.a) # 返回第一个p标签下面的第一个a标签。html中<p>节点内包含<a>节点,如果<a>还包含别的节点,还可以继续选择,这就是所谓的嵌套选择。
#print(res.p['class'])
运行结果:
<p class="lh"><a class="text-color" href="//home.baidu.com" target="_blank">关于百度</a></p>
关于百度 # p标签中的文本信息
{'class': ['lh']} # p标签的所有属性
<a class="text-color" href="//home.baidu.com" target="_blank">关于百度</a>
['lh']
方法选择器
print(res.find('p')) # .find('tagName')等同于.tagName 也是第一个
print(res.find('p', class_='article container')) #找到属性值class为article container的p标签,也可用别的属性值如:id,attr来定位。
print(res.find_all('p')) # 返回所有的p标签 返回的是一个列表,列表中每一个元素均是一个Tag类型, 也可以做属性定位。
print(res.find_all(class_="lh")) # 返回所有属性值class为lh的标签
print(res.find_all(class_="lh")[1].a['href']) # p标签下的 a标签的属性值 href
运行结果:
<p class="lh"><a class="text-color" href="//home.baidu.com" target="_blank">关于百度</a></p>
None
[<p class="lh"><a class="text-color" href="//home.baidu.com" target="_blank">关于百度</a></p>,
<p class="lh"><a class="text-color" href="http://ir.baidu.com" target="_blank">About Baidu</a></p>,
<p class="lh"><a class="text-color" href="//www.baidu.com/duty" target="_blank">使用百度前必读</a></p>,
<p class="lh"><a class="text-color" href="//help.baidu.com" target="_blank">帮助中心</a></p>,
<p class="lh"><a class="text-color" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11000002000001" target="_blank">京公网安备11000002000001号</a></p>,
<p class="lh"><a class="text-color" href="https://beian.miit.gov.cn" target="_blank">京ICP证030173号</a></p>,
<p class="lh"><span class="text-color">©2021 Baidu </span></p>,
<p class="lh"><span class="text-color">互联网药品信息服务资格证书 (京)-经营性-2017-0020</span></p>,
<p class="lh"><a class="text-color" href="//www.baidu.com/licence/" target="_blank">信息网络传播视听节目许可证 0110516</a></p>]
[<p class="lh"><a class="text-color" href="//home.baidu.com" target="_blank">关于百度</a></p>,
<p class="lh"><a class="text-color" href="http://ir.baidu.com" target="_blank">About Baidu</a></p>,
<p class="lh"><a class="text-color" href="//www.baidu.com/duty" target="_blank">使用百度前必读</a></p>,
<p class="lh"><a class="text-color" href="//help.baidu.com" target="_blank">帮助中心</a></p>,
<p class="lh"><a class="text-color" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11000002000001" target="_blank">京公网安备11000002000001号</a></p>,
<p class="lh"><a class="text-color" href="https://beian.miit.gov.cn" target="_blank">京ICP证030173号</a></p>,
<p class="lh"><span class="text-color">©2021 Baidu </span></p>,
<p class="lh"><span class="text-color">互联网药品信息服务资格证书 (京)-经营性-2017-0020</span></p>,
<p class="lh"><a class="text-color" href="//www.baidu.com/licence/" target="_blank">信息网络传播视听节目许可证 0110516</a></p>]
http://ir.baidu.com
r = requests.get(url, headers=header)
res = BeautifulSoup(r.text, 'lxml')
print(res.div.text) # text和 get_text()可以获取某一标签下的所有文本内容, string只可以获取该标签下直系的文本内容
CSS选择器
CSS选择器可以精确的定位到节点树中的每一个节点,从而我们在对数据进行筛选的时候可能会用到CSS选择器。
CSS选择器最常用的三种筛选方式分别为id、class(属性)和标签名筛选。
#开头代表选择id, 以(.)开头代表选择class。
>表示一个层级, 空格表示多个层级。
选择class = home 的<a>标签:a.home
选择id = game的<a>标签:a#game
res.select('.tang') #返回的是列表,返回属性值class为tang的标签
res.select('.tang > ul a')[0] #和 ul标签相邻,ul标签和 a标签之间有其他标签,并不相邻。
爬豆瓣top电影
要爬取的网页为:https://movie.douban.com/top250
得到正则提取来的数据后,由于每部电影的数据 information[2] 都含有一些不相关的字符以及 各个电影在这块儿的数据格式问题也都有所差异,在这块儿的数据会遇见几种不同的问题,所以要进行专门的处理。
要爬取的数据的网页结构(源码):
代码
def get_html(url):
try:
html = requests.get(url, headers=header)
return html.text
except requests.exceptions.RequestException: #包含了所有的 requests 请求异常
print(url, '请求失败')
def parse_html(html):
# 进行解析提取
pattern = '''<li>.*?<em class="">(.*?)</em>.*?<span class="title">(.*?)</span>.*?<p class="">(.*?) </p>.*?<div class="star">.*?property="v:average">(.*?)</span>.*?<span>(.*?)</span>.*?<span class="inq">(.*?)</span>.*?</li>'''
informations = re.findall(pattern, html, re.S) #informations列表每一个元素是一个元组,是一部电影的全部信息
datas = [] #datas里每一个元素是一个字典,一个元素里是一部电影的全部信息
#对提取的数据进行一些处理
for information in informations:
info = re.sub('\s', '', information[2]) # 去除空白
info = re.sub(' ', '', info) # 去除字符串 ' '
info = re.sub('...<br>', '', info)
infos = info.split('/') # infos装的是导演主演,时间,国家,电影类别
if len(infos) == 3:
infos.append(infos[2])
infos[2] = infos[1]
infos[1] = re.sub('\D', '', infos[1]) #infos[1]里是上映时间,所以把非数字删除
if infos[1] == '':
infos[1] = infos[0][-4:-1] + infos[0][-1]
infos[0] = re.sub('\d', '', infos[0])
while (len(infos) > 4): # 处理像电影 无间道 那样的数据
del infos[1]
data = {
'电影排名': information[0],
'电影名称': information[1],
'导演及主演': infos[0],
'上映时间': infos[1],
'上映地点': infos[2],
'电影类型': infos[3],
'评分': information[3],
'评价人数': information[4],
'推荐语': information[5]
}
datas.append(data)
return datas
if __name__ == '__main__':
url = 'https://movie.douban.com/top250?start=0&filter=' # start参数可以修改一次递增25
html = get_html(url)
datas = parse_html(html)
for data in datas:
for key, value in zip(data.keys(), data.values()):
print(key + ':' + value)
print('\n')
运行结果:
对程序作几点说明:
def parse_html(html):
'''Parse the HTML and extract the information you need'''
pattern = '''<li>.*?<em class="">(.*?)</em>.*?<span class="title">(.*?)</span>.*?<p class="">(.*?) </p>.*?<div class="star">.*?property="v:average">(.*?)</span>.*?<span>(.*?)</span>.*?<span class="inq">(.*?)</span>.*?</li>'''
informations = re.findall(pattern, html, re.S)
for information in informations:
fir_=re.sub('\s','',information[2])
sec_=re.sub(' ','',fir_)
thi_=re.sub('...<br>','',sec_)
this_=thi_.split('/')
print(this_)
if __name__ == '__main__':
url = 'https://movie.douban.com/top250?start=0&filter='
html = get_html(url)
parse_html(html)
运行结果:
我们可以发现,在对 information[2] 作了一些处理后,仍存在一些问题,红线和红圈的数据都是有一些问题的,需要进行进一步处理,所以需要继续解决问题。
if len(infos) == 3:
infos.append(infos[2])
infos[2] = infos[1]
infos[1] = re.sub('\D', '', infos[1]) #infos[1]里是上映时间,所以把非数字删除
if infos[1] == '':
infos[1] = infos[0][-4:-1] + infos[0][-1]
infos[0] = re.sub('\d', '', infos[0])
while (len(infos) > 4): # 处理像电影 无间道 那样的数据
del infos[1]