python网络爬虫(第二章)
(内容来自于O’Reilly(人民邮电出版社)的《Python网络爬虫权威指南》此博客仅用于记录学习,方便以后使用)
目前本系列文章(python网络爬虫笔记)更新情况:
第一章:python网络爬虫(第一章)
第二章:本文
简单实例:python网络爬虫(简单实例)
欢迎大家查阅,有不足或错误之处不吝赐教
复杂HTML解析
抓取指定颜色的文字
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen(‘http://www.pythonscraping.com/pages/warandpeace.html')
bs = BeautifulSoup(html.read(), 'html.parser')
nameList = bs.find_all('span', {'class': 'green'})
for name in nameList:
print(name.get_text)
网址 http://www.pythonscraping.com/pages/warandpeace.html 里面是英文版的《战争与和平》,其中的人名全部用绿色标注,对话内容用红色标注
通过BeautifulSoup对象,可以用find_all函数提取只包含在标签里的文字,这样可以得到一个人物名称的Python列表
find() 和 find_all()
find_all(tag, attributes, recursive, text, limit, keywords)
find(tag, attributes, recursive, text, keywords)
参数解释:
标签参数tag:传递一个标签的名称或多个标签名称组成的Python列表做标签参数。如:
.find_all([‘h1’, ‘h2’, ’h3’, ‘h4’, ‘h5’, ‘h6’])
可以获得文档中所有标题标签的列表
属性参数attributes用一个Python字典封装一个标签的若干属性和对应的属性值。例如下面这个函数会返回HTML文档里红色与绿色两种颜色的span标签:
.find_all(‘span’, {‘class’: {‘green’, ‘’red}})
递归参数recursive是一个布尔变量,默认设置为True,表示会查找标签参数的所有子标签,以及子标签的子标签(若设置为False, 则只查找文档的一级标签)
文本参数text,用标签的文本内容去匹配
Namelist = bs.find_all(text = ‘the prince’)
print(len(nameList))
上述代码输出的是the prince在网页中出现的次数
范围限制参数limit显然只适用于find_all方法。find其实等价于limit等于1时的find_all
关键词参数keyword,可以选择具有指定属性的标签
导航树
http://www.pythonscraping.com/pages/page3.html
此网址为虚拟的在线购物网站,用作这一部分的要抓取的示例网页
html导航树的纵向和横向导航
# 处理子标签和其他后代标签
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen(‘http://www.pythonscraping.com/pages/page3.html')
bs = BeautifulSoup(html, 'html.parser')
for child in bs.find('table', {'id': 'giftList'}).children:
print(child)
children子标签:子标签是父标签的下一级
descendants后代标签:父标签下面的所有级别的标签
上述代码会打印giftList表格中所有产品的数据行,包括最开始的列名行。
# 处理兄弟标签
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen(‘http://www.pythonscraping.com/pages/page3.html')
bs = BeautifulSoup(html, 'html.parser')
for sibling in bs.find('table', {'id': 'giftList'}).tr.next_siblings:
print(sibling)
next_siblings可以获得除自己本身的兄弟标签
在带标题行的表格中使用,能够获得除了标题行以外的所有行
相类似的还有previous_siblings
# 处理父标签
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen(‘http://www.pythonscraping.com/pages/page3.html')
bs = BeautifulSoup(html, 'html.parser')
print(bs.find('img',
{'src': '../img/gifts/img1.jpg'})
.parent.previous_sibling.get_text())
父标签查找函数:parent和parents
上述代码的查找步骤:
1、首先选择图片标签src=“…_img_gifts/img1.jpg”
2、选择图片标签的父标签(在示例中是td标签)
3、选择td标签的前一个兄弟标签previous_sibling(在示例中是包含美元价格的td标签)
4、选择标签中的文字,“$15.00”
正则表达式
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
html = urlopen(‘http://www.pythonscraping.com/pages/page3.html')
bs = BeautifulSoup(html, 'html.parser')
images = bs.find_all('img',
{'src': re.compile('../img/gifts/img.*.jpg')})
for image in images:
print(image[‘src’])
上述代码会打印出图片的相对路径,都是以…_img_gifts/img开头,以.jpg结尾
在.compile(’…_img_gifts/img.*.jpg’)中的图片的相对路径表达就使用到了正则表达式
正则表达式可以作为BeautifulSoup语句的任意一个参数,灵活地查找目标元素
获取属性
myTag.attrs#属性返回的是一个python的字典对象
myImgTag.attrs[‘src’]#获取图片的源位置src
Lambda表达式
(非常有用,但暂时还没实践过QAQ)
本质上是一个函数,可以作为变量传入另一个函数,类似于
f(g(x), y) 或 f(g(x), h(y))的形式
BeautifulSoup允许我们把特定类型的函数作为参数传入find_all函数。唯一的限制条件是这些函数必须把一个标签对象作为参数并且返回布尔类型的结果。BeautifulSoup用这个函数来评估它遇到的每个标签对象,最后把评估结果为“真”的标签保留,把其他标签剔除
bs.find_all(lambda tag: len(tag.attrs) == 2)
这里,作为参数传入的函数是len(tag.attrs) == 2。当该参数为真时, find_all函数将返回tag。即找出带有两个属性的所有标签,类似于:
再比如,以下两行代码可以互相替换(所以Lambda表达式可以替代现有的BeautifulSoup函数):
bs.find_all(lambda tag: tag.get_text() ==
‘Or maybe he\’s only resting?’)#使用了lambda表达式
bs.find_all(‘’, text = ‘Or maybe he\’s only resting?’)