python 网络爬虫 - BeautifulSoup 爬取网络数据

0. 前言

在介绍BeautifulSoup模块前, 我们先分析一下我们要爬取的网页结构是什么样的。通常网页都包含层叠样式表(英文全称:Cascading Style Sheets),例如。 推荐使用谷歌浏览器或者火狐浏览器方便快捷查看网页结构。例如在chrome中百度首页右击,选择'inspect',即可查看到网页结构,以及各个标签层级关系。

image

1. 创建爬虫爬取网页

爬取网站:url =www.pythonscraping.com/pages/warandpeace.html

网页如图所示,有红色和绿色字体。在绿色字体处右键选择“inspect”分析标签结构可知。绿色字体均包含在标签GreenText当中。

image

1.1 抓取网页


from urllib.request import urlopen

from bs4 import BeautifulSoup

url ='http://www.pythonscraping.com/pages/warandpeace.html'

html= urlopen(url) #抓取了该url网页

soup = BeautifulSoup(html) #使用BeautifulSoup对网页进行解析

name_list = soup.find_all("span",{'class': 'green'})#find_all抓取所有绿色字体,返回list

for name in name_list:

    print(name.get_text()) #get_text()函数剔除字符串中所有tag符号只保留tag中包含的文本

2. find() 和 find_all()

推荐有能力的各位查看BeautifulSoup官方文档,这里简单讲解一下。
请看以下比较:

  find_all(tag, attributes, recursive, text,limit, keywords)
# find_all(标签, 属性, 递归, 文本,限制查询数量, 关键字)
  find(tag,attributes, recursive, text,keywords)
#find 相当于find_all(,limit=1)

绝大多数的情况我们只会遇到前两个参数,tag和attributes。tag和attributes都可以查找多个值。


from urllib.request import urlopen

from bs4 import BeautifulSoup

url ='http://www.pythonscraping.com/pages/warandpeace.html'

html= urlopen(url) #抓取了该url网页

soup = BeautifulSoup(html) #使用BeautifulSoup对网页进行解析

hs = soup.find_all({'h1', 'h2'})#find_all抓取所有绿色字体,返回list

print(hs)

得到结果:

[<h1>War and Peace</h1>, <h2>Chapter 1</h2>]

同理,属性参数也可以包含多个属性。例如需要查找所有绿色和红色的文本:

....
words = soup.find_all('span', {'class':{'green', 'red'}})
print(len(words))

有兴趣的朋友可以看看绿色和红色的tag分别有多少个。

关键字参数可以用来选择包含特定属性的是标签,比如:

all_text = soup.find_all(id = 'text')
print(all_text[0].get_text()

细心的朋友可能会注意到,其实关键字参数匹配完全可以用属性参数替换。

soup.find_all(id='text')
soup.find_all("",{"id":"text"})
soup.find_all(class="green")
soup.find_all('',{'class':'green'})

注意: 在BeautifulSoup4版本中find_all 和findAll 是一样的。find_all是新版本的写法,findAll是旧版本的写法,但是目前二者在版本4中通用。

3. 1子节点和子孙节点

soup.body.h1# 选中body 标签下的h1,这个h1 标签是body标签的子节点

同理,soup.div.find_all('img')会找到所有div里面的img标签。
.children 和.descendants
对比代码如下:

html = urlopen('http://www.pythonscraping.com/pages/page3.html')
soup = BeautifulSoup(html, 'lxml')
children = soup.find('table',{'id':'giftList'}).children
descendants = soup.find('table',{'id':'giftList'}).descendants
sum = 0
for child in children:
    print(child)
    sum +=1
print(sum)
sum2 = 0
for descendant in descendants:
    sum2+=1
    print(descendant)
print(sum2)

运行结果可知 sum = 13, sum2 = 86
取descendants的第一部分作比较可以发现

<tr><th>#=============<tr>是soup.find('table',{'id':'giftList'})的子节点====
Item Title
</th><th>
Description
</th><th>
Cost
</th><th>
Image
</th></tr>#============<tr>是soup.find('table',{'id':'giftList'})的子节点====
<th>        #============<th>是<tr>的子节点,('table',{'id':'giftList'})的子孙节点==
Item Title
</th>       #============<th>是<tr>的子节点,('table',{'id':'giftList'})的子孙节点==

Item Title#=========文本是<th>标签的内容,也是子孙节点================

<th>#============同上====================
Description
</th>

Description

<th>
Cost
</th>

Cost
....

对比可知,children只列出了<tr>标签所包含的内容。而descendants列出了所有包含的标签节点以及文本,即<tr>子标签中的所有子子孙孙标签都会查找返回。

3.2 父节点

通常情况下我们更经常查找子节点,而在某些特定情况下会用到查询父节点,.parents 和 .parent。

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen('http://www.pythonscraping.com/pages/warandpeace.html')
soup = BeautifulSoup(html)
print(soup.find('img', {'src':'../img/gifts/img1.jpg'}).parent.previous_sibling.get_text())

分析一下代码是如何工作的。

<tr>
--<td>
--<td>(3)
    --"$15.00"(4)
--s<td>(2)
    --<img src="../img/gifts/img1.jpg">(1)

1.首先定位到含src="../img/gifts/img1.jpg"的标签img。
2.选中img标签的父节点s<td>.
3.选中s<td>的上一个同层级标签<td>
4.选取<td>标签中的文字

4. 处理同辈节点和父辈节点
BeautifulSoup的next_siblings()函数非常适用于表格查找,尤其是带有标题的表格。

image.png

from urllib.request import urlopen
from bs4 import BeautifulSoup


html = urlopen("http://www.pythonscraping.com/pages/page3.html")
soup = BeautifulSoup(html, 'lxml')

siblings = soup.find("table",{'id':'giftList'}).tr.next_siblings
sum = 0
for sibling in siblings:
    print(sibling)
    sum+=1
print(sum)

结果为:



<tr class="gift" id="gift1"><td>
Vegetable Basket
</td><td>
This vegetable basket is the perfect gift for your health conscious (or overweight) friends!
<span class="excitingNote">Now with super-colorful bell peppers!</span>
</td><td>
$15.00
</td><td>
<img src="../img/gifts/img1.jpg"/>
</td></tr>


<tr class="gift" id="gift2"><td>
Russian Nesting Dolls
</td><td>
Hand-painted by trained monkeys, these exquisite dolls are priceless! And by "priceless," we mean "extremely expensive"! <span class="excitingNote">8 entire dolls per set! Octuple the presents!</span>
</td><td>
$10,000.52
</td><td>
<img src="../img/gifts/img2.jpg"/>
</td></tr>

...

11
0
[Finished in 2.2s]

代码输出产品表中的所有产品,除了首行标题。因为:
1. 查找对象本身不是自己的同辈,因此使用sibling相关函数时查找对象都会被跳过。
2.代码使用的是next siblings,因此会返回查找对象的下一个(些)同辈节点。

补充:除了next_siblings,记住previous_siblings经常用来查找已知最后一行容易定位且不需要抓取的情况。当然,next_sibling 和 previous_sibling 可以用来查找一个同辈节点。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容