Python网络爬虫案例实战:解析网页:BeautifulSoup 解析网页

Python网络爬虫案例实战:解析网页:BeautifulSoup 解析网页

BeautifulSoup是Python的一个HTML解析框架,利用它可以方便地处理HTML和 XML文档。BeautifulSoup有3和4两个版本,目前3已经停止开发。所以这里学习最新的 BeautifulSoup4。
首先是利用pip安装 BeautifulSoup。使用下面的命令。

pip install beautifulsoup4

安装 BeautifulSoup 后,就可以开始使用它了。
BeautifulSoup 只是一个HTML解析库,所以如果想解析网上的内容,第一件事情就是把它下载下来。对于不同的网站,可能对请求进行过滤。糗事百科的网站就会直接拒绝没有UA的请求。所以如果要爬这样的网站,首先需要把请求伪装成浏览器的样子。具体网站具体分析,经过测试,糗事百科只要设置了UA 就可以爬取到内容,对于其他网站,你需要测试一下才能确定什么设置可用。
有了Request对象还不够,还需要实际发起请求才行。下面代码的最后一句就使用了Python3的urllib库发起了一个请求。urlopen(req)方法返回的是Reponse对象,调用它的read()函数获取整个结果字符串。最后调用 decode(‘utf-8’)方法将它解码为最终结果,如果不调用这一步,那么汉字等非 ASCII字符就会变成\xXXX这样的转义字符。

>>> import urllib.request as request
>>> user_agent = 'Mozilla/5.0(Windows NT 10.0; Win64; x64)ApplelebKit/537.36(KHTML, like Gecko)Chrome/56.0.2924.87 Safari/537.36'
>>> headers = {'User-Agent':user_agent}
>>> req = request.Request('http://www.qiushibaike.com/',headers = headers)
>>> page = request.urlopen(req).read().decode('utf-8')

有了文档字符串,就可以开始解析文档了。第一步是建立 BeautifulSoup对象,这个对象在bs4 模块中。注意,在建立对象的时候可以额外指定一个参数,作为实际的HTML解析器。解析器的值可以指定html.parser,这是内置的HTML解析器。更好的选择是使用下面的1xml解析器,不过它需要额外安装一下,使用pip install 1xml就可以安装。

import bs4
soup = bs4.BeautifulSoup(page,"lxml")

有了BeautifulSoup 对象,就可以开始解析了。首先介绍BeautifulSoup的对象种类,常用的有标签(bs4.element.Tag)以及文本(bs4.element.NavigableString)等,其中,注解等对象不常用,在此不展开介绍。在标签对象上,可以调用一些查找方法例如find_all等,还有一些属性返回标签的父节点、兄弟节点、直接子节点、所有子节点等。在文本对象上,可以调用.string属性获取具体文本。
基本所有 BeautifulSoup的遍历方法操作都需要通过 BeautifulSoup 对象来使用。使用方式主要有两种:一是直接引用属性,例如 soup.title,会返回第一个符合条件的节点;二是通过查找方法,例如find_all,传入查询条件来查找结果。
接下来了解查询条件。查询条件可以是:字符串,会返回对应名称的节点;正则表达式,按照正则表达式匹配;列表,会返回所有匹配列表元素的节点;真值 True,会返回所有标签节点,不会返回字符节点;方法,可以编写一个方法,按照自己的规则过滤,然后将该方法作为查询条件。
BeautifulSoup 支持Python标准库中的HTML解析器,还支持一些第三方的解析器。表5-2列出了主要的解析器及其优缺点。
在这里插入图片描述
使用lxml的解析器将会解析得更快,建议大家使用。
[例5-5]利用requests 和 BeautifulSoup 爬取猫眼电影排行信息。

import requests
from bs4 import BeautifulSoup
import os 
import time
 
start = time.clock()  # 添加程序运行计时功能。 
file_path = 'D:\python3.6\scrapy\猫眼' # 定义文件夹,方便后续check文件夹是否存在
file_name = 'maoyan.txt'   # 自定义命名文件名称,
file = file_path+'\\'+file_name     # 创建文件全地址,方便后续引用 
url = "http://maoyan.com/board/4"  # 获取url的开始页 
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"}
 
def Create_file(file_path,file):   # 定义 检查和创建目标文件夹和文件的函数	
	if os.path.exists(file_path)== False: # check文件夹不存在
		os.makedirs(file_path)   # 创建新的自定义文件夹
		fp = open(file,'w')   # 创建新的自定义文件
	# "w" 以写方式打开,只能写文件,如果文件不存在,创建该文件;如果文件已存在,先清空,再打开文件	
	elif os.path.exists(file_path)== True: # check文件夹存在
		with open(file, 'w', encoding='utf-8') as f: # 打开目标文件夹中的文件
			f.seek(0)
	# f.seek(offset[,where])把文件指针移动到相对于where的offset位置。where为0表示文件开始处,这是默认值 ;1表示当前位置;2表示文件结尾
			f.truncate()
	#清空文件内容,注意:仅当以 "r+" "rb+" "w" "wb" "wb+"等以可写模式打开的文件才可以执行该功能 
def get_all_pages(start):
# 定义获取所有pages页的目标内容的函数	
	pages=[]	
	for n in range(0,100,10):
	#获取offset的步进值,注意把int的n转换为str
	#遍历所有的url,并获取每一页page的目标内容
		if n==0:
			url=start
		else:
			url=start+'?offset='+str(n)			
		r = requests.get(url, headers=headers) 
		soup = BeautifulSoup(r.content, 'lxml')
		page= soup.find_all(name='dd')	
		#获取该gage的所有dd节点的内容		
		pages.extend(page)
		#将获取的所有page list扩展成pages,方便下面遍历每个dd节点内容		
	return pages
	#返回所有pages的dd节点的内容,每个dd节点内容都以list方式存储其中 
	
Create_file(file_path,file) 
text = get_all_pages(url)
 
for film in text:
#遍历列表 text中的所有元素,也就是每个dd节点内容
#这个for循环应该优化成 自定义函数形式;
	dict ={}
	# 创建空dict	
	# print(type(film)) #确认 film 属性为tag,故可以使用tag相关的方法处理film
	# print('*'*50) #可以分隔检查输出的内容,方便对照 
	dict['Index']=film.i.string #选取film的第一个子节点 i 的的string属性值	
	comment1 = film.div.div.div	#获取第三重直接子孙节点,例如下面注释中的<div class="movie-item-info"> 节点全部元素	
	name= comment1.find_all(name='p')[0].string
	star = comment1.find_all(name='p')[1].string
	releasetime = comment1.find_all(name='p')[2].string	
	dict['name']=name
	dict['star']=str.strip(star)
	dict['releasetime']=releasetime		
	comment2 = comment1.find_next_sibling() 
	#获取第三重直接子孙节点的next节点,例如下面注释中的<div class="movie-item-info"> 节点全部元素
	# print(comment2)	 # 检查comment2是否为目标文本
	sco1=comment2.i.string
	sco2=comment2.i.find_next_sibling().string	
	# print(type(sco1)) # 判断sco1 为tag类型
	# print(sco1) # 检查sco1是否为目标输出内容 
	score = (sco1.string+str.strip(sco2))# 获取合并后的score字符串
	dict['score']=score	
	print(dict) # 检查dict是否为目标输出内容	
	with open(file, 'a', encoding='utf-8') as f: # 以打开目标file文件
		f.write(str(dict)+'\n')  #注意添加换行符 '\n',实现每个dict自动换行写入txt中		
end = time.clock() # 添加程序运行计时功能。
print('抓取完成','\n','耗时:',end-start) # 添加程序运行计时功能。

运行程序

{'Index': '1', 'name': '我不是药神', 'star': '主演:徐峥,王传君,周一围', 'releasetime': '上映时间:2018-07-05', 'score': '9.6'}
{'Index': '2', 'name': '肖申克的救赎', 'star': '主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿', 'releasetime': '上映时间:1994-09-10(加拿大)', 'score': '9.5'}
{'Index': '3', 'name': '海上钢琴师', 'star': '主演:蒂姆·罗斯,比尔·努恩 ,克兰
伦斯·威廉姆斯三世', 'releasetime': '上映时间:2019-11-15', 'score': '9.3'}
{'Index': '4', 'name': '绿皮书', 'star': '主演:维果·莫腾森,马赫沙拉·阿里,琳达·卡德里尼', 'releasetime': '上映时间:2019-03-01', 'score': '9.5'}
{'Index': '5', 'name': '霸王别姬', 'star': '主演:张国荣,张丰毅,巩俐', 'releasetime': '上映时间:1993-07-26', 'score': '9.4'}
{'Index': '6', 'name': '美丽人生', 'star': '主演:罗伯托·贝尼尼,朱斯蒂诺·杜拉 诺,赛尔乔·比尼·布斯特里克', 'releasetime': '上映时间:2020-01-03', 'score': '9.3'}
{'Index': '7', 'name': '这个杀手不太冷', 'star': '主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼', 'releasetime': '上映时间:1994-09-14(法国)', 'score': '9.4'}    
{'Index': '8', 'name': '星际穿越', 'star': '主演:马修·麦康纳,安妮·海瑟薇,杰西卡·查斯坦', 'releasetime': '上映时间:2014-11-12', 'score': '9.3'}
{'Index': '9', 'name': '小偷家族', 'star': '主演:中川雅也,安藤樱,松冈茉优', 'releasetime': '上映时间:2018-08-03', 'score': '8.1'}
{'Index': '10', 'name': '盗梦空间', 'star': '主演:莱昂纳多·迪卡普里奥,渡边谦,约瑟夫·高登-莱维特', 'releasetime': '上映时间:2010-09-01', 'score': '9.0'}   
e:/桌面Desktop/Python网络爬虫实战/example/5/p5_5.py:73: DeprecationWarning: time.clock has been deprecated in Python 3.3 and will be removed from Python 3.8: use time.perf_counter or time.process_time instead
  end = time.clock() # 添加程序运行计时功能。
抓取完成
 耗时: 5.0513751

在这里插入图片描述

  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值