Web scraping with Python-笔记Python语言与信息数据获取和机器学习

python 网络爬虫 - BeautifulSoup 爬取网络

2018-02-25  本文已影响126人  查德笔记

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 可以用来查找一个同辈节点。

上一篇下一篇

猜你喜欢

热点阅读