python网络爬虫-复杂HTML解析

     如何进行复杂HTML的解析,需要在实施中注意以下几个方面:

(1)寻找“打印此页”的链接,或者看看网站状态有没有HTML样式更友好的移动版(把自己的请求头信息设置成处于移动设备的状态,然后接收网站的移动版);

(2)寻找隐藏在JavaScript文件里的信息。要实现这一点,你可能需要查看网页加载的JavaScript文件。我曾经要把一个网站上的街道地址(以经度和纬度呈现的)整理成格式整洁的数组时,查看过内嵌谷歌地图的JavaScript文件,里面有每个地址的标记点。

(3)虽然网站标题通常会用到,但是这个信息也许可以从网页的URL链接中获取。

(4)如果你要找的信息只存在于一个网站上,别处没有,那你确实运气不佳。如果不止限于这个网站,那么你可以找找其它数据源。有没有其它网站也显示了同样的数据?网站上显示的数据是不是从其他网站上抓取后攒起来。

1. 再次使用BeautifulSoup

     在上面的文章中,我们演示了BeautifulSoup的安装和使用过程,本篇文章中我们将继续使用BeautifulSoup。对于现代网站页面,CSS是大多数网站都会使用的,下面的的程序通过css的标签来进行网络数据的收集:

from urllib.request import urlopen
from bs4 import BeautifulSoup
html=urlopen("http://www.pythonscraping.com/pages/warandpeace.html")
bsObj=BeautifulSoup(html,"html.parser")
通过BeautifulSoup对象,我们可以使用findAll函数抽取只包含在<span class="green"></span>标签里的文字,这样就可以得到一个人物名称的Python列表(findAll是一个非常灵活的函数,后面会经常使用)

nameList=bsObj.findAll("span",{"class":"green"})
for name in nameList:
       print(name.get_text())
执行结果如下:

成功地完成了指定信息的爬取。我们调用了bsObj.tagName只能获取页面中的第一个指定的标签。我们使用bsObj.findAll(tagName,tagAttributes)可以获取页面中所有指定的标签,不再是第一个了。获取了人名列表后,程序遍历列表中所有的名字,然后打印name.get_text(),就可以把标签中的内容分开显示了。

      这边会涉及到一个问题,也就是什么时候使用get_text(),什么时候应该保留标签?

     .get_text()会把你正在处理的HTML文档中的所有的标签都清除,然后返回一个只包含文字的字符串。假如你正在处理一个包含许多超链接、段落和标签的大段源代码,那么,使用,get_text()会把这些超链接、段落和标签都清除掉,只剩下遗传不带标签的文字。

       用BeautifulSoup对象查找你想要的信息,比直接在HTML文本里查找信息要简单地多。通常情况在你准备打印、存储和操作数据时,应该最后才使用.get_text()。一般情况下,你应该尽可能地保留HTML文档的标签结构。

2. 区分BeautifulSoup中的find和findAll()

    BeautifulSoup里的find()和findAll()可能是你最常用的两个函数,你可以通过标签的不同属性轻松的过滤HTML页面,查找需要的标签组或单个标签。这两个函数非常相似,BeautifulSoup文档里两者的定义如下:

findAll(tag,attributes,recursive,text,limit,keywords)
find(tag,attributes,recursive,text,keywords)
     我们一般只会使用前两个参数tag和attributes。标签tag前面已经介绍过-你可以传入一个标签的名称或多个标签名称组成的Python列表做参数。例如,下面的代码将返回一个包含HTML文档中所有标题标签的列表:

findAll("h1","h2","h3","h4","h5","h6")
      属性参数attributes是一个用Python字典封装一个标签的若干属性和对应的属性值。例如,下面这个函数会返回HTML文档里红色和绿色两种颜色的span标签:

findAll("span",{"class":{"green","red"}})
     递归参数recursive是一个布尔变量。你想抓取HTML文档结构里多少层的信息呢?如果recursive为true,findAll就会根据你的要求去查找标签参数的所有子标签,以及子标签的子标签。如果recursive设置为false,findAll就值查找文档的额一级标签。findAll默认是支持递归查找的(recursive默认值是true);一般情况下这个参数不需要设置,除非你真正了解自己需要哪些消息,而且抓取速度非常重要,那时你可以设置递归函数。

     文本参数text有点不同,它是用标签的文本内容去匹配,而不是标签的属性。假如我们想查找前面网页中包含“the price”内容的标签数量,我们可以把之前的findAll方法换成下面的代码:

nameList=bsObj.findAll(text="the prince")
print(len(nameList))
执行结果为7个。

    范围限制参数limit,显然只用于findAll方法。find其实等价于findAll的limit等于1的情形。如果你只对网页中获取的前x项结果感兴趣,就可以设置它。但是要注意,这个参数设置之后,获得的前几项结果时按照网页上的顺序排序的,未必是你想要的那前几项。

     还有一个关键词参数keyword,可以让你选择那些具有指定属性的标签,例如:

allText=bsObj.findAll(id="text")
print(allText[0].get_text())
     虽然关键词参数keyword在一些场景中很有用,但是,它是BeautifulSoup在技术上做的一个冗余功能。任何用关键词参数能够完成的任务,都能适用后续的技术解决。例如,下面两行代码时完全一致的:

bsObj.findAll(id="text")
bsObj.findAll("",{"id":"text"})
另外,用keyword偶尔会出现问题,尤其是在用class属性查找标签的时候,因为class是Python中受保护的关键字。也就是说,class是Python语言的保留字,在Python程序里是不能当做变量或者参数名适用的。假如你运行下面的代码,Python就会因为你误用class关键字而产生一个语法错误:

bsObj.findAll(class="green")
不过,你可以用BeautifulSoup提供的有点臃肿的方案,在class后面增加一个下划线:

bsObj.findAll(class_="green")
另外,你也可以用属性参数把class用引号括起来。

bsObj.findAll("class"="green")

      总结一下,find和findAll中的通过标签参数tag把标签列表传入,其实就是一个“或”关系过滤器,而关键词参数keyword就是让你增加一个“与”关系的过滤器来简化工作

3. 其他BeautifulSoup对象

      看到这里,你已经见过BeautifulSoup库里的两种对象了

(1)BeautifulSoup对象

      前面代码示例中的bsObj

(2)标签Tag对象

      BeautifulSoup对象通过find和findAll,或者直接调用子标签获取的一列对象或单个对象,就像:

bsObj.div.h1

(3)NavigableString对象

      用来表示标签里的文字,不是标签(有些函数可以操作和生成NavigableString对象,而不是标签对象)

(4)Comment对象

     用来查找HTML文档的注释标签,<!--   -->

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值