假如你已经确定了目标内容,但是你的标签隐藏在一个复杂的HTML的标签里,带有许多没用的标签或HTML属性,如果网站管理员对网站稍作修改之后,你写好的爬虫就会失效,我们该怎么做呢?
- 把网站设置成移动设备的状态
- 寻找隐藏在JavaScript文件里的信息,要实现这一点,你可能需要查看网页加载的JavaScript文件
- 可以从URL里获取网页标题
- 考虑别的网站是否有同样的数据
Beautifulsoup的骚操作
每一个网站都会有层叠样式表(css),CSS可以让HTML差异化,可以使那些具有相同标签的内容有不同的样式,网络爬虫可以通过class属性区分出不同的标签,因为CSS能通过属性准确的呈现网站的样式.
<ul>
<li class="static_nav__discover">
<a href="/editors/all"><span class="translation_missing" title="translation missing: zh-CN.static_pages.nav.discover">Discover</span></a>
</li>
<li class="static_nav__about">
<a href="//about.500px.com/">About</a>
</li>
<li class="static_nav__licensing">
<a href="/licensing">Licensing</a>
</li>
</ul>
我们来爬取www.500px.com
网页的li标签class="static_nav__about"
from bs4 import BeautifulSoup
from urllib.request import urlopen
html = urlopen("https://500px.com")
bsObj = BeautifulSoup(html)
li_list = bsObj.findAll("li",{"class":"static_nav__about"})
for i in li_list:
print(i.get_text())
About
我们发现class="static_nav__about"
这个类在li
标签下只有一个内容.
在什么时候用get_text()?
.get_text()会把标签清除只留下文字内容,如果你需要的信息包含着大量的超链接,段落和标签的大段源代码,那么就不能用
.get_text()
因为它会把他们都清除,只留下文本信息,我们在使用beasoup爬取网站的时候最好保留标签.
BeautifulSoup的find()和findAll()
在我们使用BeautifulSoup的时候使用最多的就是这两个函数,它们可以通过标签的不同的属性轻松过滤掉HTML页面获取你想要的信息,查找需要的标签组或者单个标签.
语法:
findAll(tag,attributes,recursive,text,limit,keywords)
find(tag,attributes,recursive,text,keywords)
我们经常使用的参数是:tag
和attributes
,tag是标签名称,你可以传一个或者多个标签做参数例如:.findAll({"h1","h2","h3"})
,属性参数attributes使用一个字典封装一个标签的若干属性和对应的值例如:.findAll("li",{"class":"static_nav__about"})
,递归参数recursive是一个布尔值,如果为Ture就会查找所有子标签,如果是false就只会查找一级标签,默认为Ture.
文本参数Text是根据标签的文本内容去匹配,而不是用标签的属性,加入我们要查找文本里含有the
这个单词的标签数量:
name_list = bsObj.findAll(text='the')
print(len(name_list))
范围参数limit,只有.findAll()
方法有,find方法等价于findAll的limit参数为1,可以设置参数来获取前几项参数,但是是按照网页上的排序
关键字参数Keyword,可以选择指定属性的标签:
text = bsObj.findAll(id='text')
print(text[0].get_text())
注意
关键字参数在beautifulsoup中是一个不太完美的参数,因为在HTML中有些属性在python中是被保护的,例如class,所以尽量不要用关键词参数,利用其它的参数代替
BeautifulSoup的对象
- BeautifulSoup对象
前面代码实例中的bsObj
- 标签Tag对象
bsObj通过find和findAll,或者直接调用子标签获取的一列对象或单个对象:bsObj.div.h1
- NavigableString对象
用来表示标签里的文字,不是标签
- Comment对象
用来查找HTML中的注释标签
导航树
findAll函数通过标签的名称和属性来查找标签,但是如果你需要通过标签在文档中的位置来查找,就需要使用导航树,假如我们将一个HTML页面映射成一棵树:
-heard
-body
-div
-h1
-div
-table
-tr
-th
-th
-tr
-td
-td
-span
-td
-img
- ...
处理子标签和其他后代标签
在beautifulsoup库里边孩子标签和后代标签有显著的不同,子标签就是父级标签的下一级标签,后代标签就是一个父级标签下所有级别的标签举个例子:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("https://www.500px.com")
bsObj = BeautifulSoup(html)
for tag_child in bsObj.find('ul').children:
print(tag_child)
<li class="static_nav__discover">
<a href="/editors/all"><span class="translation_missing" title="translation missing: en.static_pages.nav.discover">Discover</span></a>
</li>
<li class="static_nav__about">
<a href="//about.500px.com/">About</a>
</li>
<li class="static_nav__licensing">
<a href="/licensing">Licensing</a>
</li>
如果是dexcendants()
函数的话就是打印所有后代标签
处理兄弟标签
在处理HTML里的兄弟标签时我们用Beautifulsoup库里的next_siblings()
函数例如:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("https://www.500px.com")
bsObj = BeautifulSoup(html)
for tag_sibling in bsObj.find('ul').li.next_siblings:
print(tag_sibling)
<li class="static_nav__about">
<a href="//about.500px.com/">About</a>
</li>
<li class="static_nav__licensing">
<a href="/licensing">Licensing</a>
</li>
注意
next_siblings()函数只会返回选中标签的后面的兄弟标签,除了标题行.在写代码的时候为了爬虫更稳定我们要充分利用好标签的属性查找,
previous_siblings()
是找前一个
父级标签的处理
查找父级标签的需求要比其他的少很多,通常我们需要观察HTML页面,我们都是从最上层标签开始的然后思考我们需要的数据在哪,我们也可以用父级标签来找函数是.parent
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("https://www.500px.com")
bsObj = BeautifulSoup(html)
print(bsObj.find('li',{'class':"static_nav__about"}).parent)
<ul>
<li class="static_nav__discover">
<a href="/editors/all"><span class="translation_missing" title="translation missing: en.static_pages.nav.discover">Discover</span></a>
</li>
<li class="static_nav__about">
<a href="//about.500px.com/">About</a>
</li>
<li class="static_nav__licensing">
<a href="/licensing">Licensing</a>
</li>
</ul>
补充
1.获取属性
如果要通过标签获取属性的话只需要输入myTag.attrs
就行
2.lambda表达式
在python中我们已经知道了匿名函数的用法,在Beautfulsoup库中,我们可以利用匿名函数来做条件进行查找例如查找有两个属性的标签:
soup.findAll(lambda tag: len(tag.attrs)==2)