Beautifulsoup---复杂的HTML爬取

假如你已经确定了目标内容,但是你的标签隐藏在一个复杂的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)

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

推荐阅读更多精彩内容