关于爬虫中常见的两个网页解析工具的分析 —— lxml / xpath 与 bs4 / BeautifulSoup
http://www.cnblogs.com/binye-typing/p/6656595.html
读者可能会奇怪我标题怎么理成这个鬼样子,主要是单单写 lxml 与 bs4 这两个 py 模块名可能并不能一下引起大众的注意,一般讲到网页解析技术,提到的关键词更多的是 BeautifulSoup 和 xpath ,而它们各自所在的模块(python 中是叫做模块,但其他平台下更多地是称作库),很少被拿到明面上来谈论。下面我将从效率、复杂度等多个角度来对比 xpath 与 beautifulsoup 的区别。
效率
使用复杂度
def get_nav(self,response):
# soup = BeautifulSoup(response.body_as_unicode(), 'lxml')
# nav_list = soup.find('ul', id='nav').find_all('li')
model = etree.HTML(response.body_as_unicode())
nav_list = model.xpath('//ul[@id="nav"]/li')
for nav in nav_list[1:]:
# href = nav.find('a').get('href')
href = nav.xpath('./a/@href')[0]
yield Request(href, callback=self.get_url)
可以看到 xpath 除了其特殊的语法看上去有些别扭(跟正则表达式似的)以外,它在代码简洁度上还是可观的,只是所有 xpath 方法的返回结果都是一个 list ,如果匹配目标是单个元素,对于无脑下标取0的操作,强迫症患者可能有些难受。相比之下,BeautifulSoup 这一长串的 find 与 find_all 方法显得有些呆板,如果碰到搜索路线比较曲折的,比如:
# href = article.find('div', class_='txt').find('p', class_='tit blue').find('span').find('em').find('a').get('href')
href = article.xpath('./div[@class="txt"]//p[@class="tit blue"]/span/em/a/@href')[0]
这种情况下,BeautifulSoup 的写法就显得有些让人反胃了,当然一般情况下不会出现这么长的路径定位。
功能缺陷总结——BeautifulSoup
BeautifulSoup 在使用上的一个短板,就是在嵌套列表中去匹配元素的时候会显得很无力,下面是一个例子(具体网页结构可根据 index_page 在浏览器打开进行审查):
class RankSpider(spider):
name = 'PCauto_rank'
index_page = 'http://price.pcauto.com.cn/top/hot/s1-t1.html'
api_url = 'http://price.pcauto.com.cn%s' def start_requests(self):
yield Request(self.index_page, callback=self.get_left_nav) # 测试 BeautifulSoup 是否能连续使用两个 find_all 方法
def get_left_nav(self,response):
# model = etree.HTML(response.body_as_unicode())
# nav_list = model.xpath('//div[@id="leftNav"]/ul[@class="pb200"]/li//a[@class="dd "]')
soup = BeautifulSoup(response.body_as_unicode(), 'lxml')
nav_list = soup.find('div', id='leftNav').find('ul', class_='pb200').find_all('li').find_all('a', class_='dd')
for sub_nav in nav_list:
href = self.api_url % sub_nav.xpath('./@href')[0]
yield Request(href, callback=self.get_url) def get_url(self):
pass
使用注释部分的 xpath 写法没什么问题,可实现准确定位,但用到 BeautifulSoup 去实现相应逻辑的时候,就要连续使用两个 find_all 方法 ,显然这种写法不符合规范,运行的时候会报 AttributeError: 'ResultSet' object has no attribute 'find_all' 错误,这时候我们要实现这种匹配,只能先去遍历各个 li ,然后调 find_all 方法找到 li 下的各个 a 标签,实在繁琐,所以这种场景用 xpath 来解决会省下不少麻烦。
当然这里我只是单单为了诠释这么个问题才在故意在拿目标 url 时分这么多级的,实际开发中我这里用的是:
# nav_list = model.xpath('//div[@id="leftNav"]///a[@class="dd "]')
nav_list = soup.find('div', id='leftNav').find_all('a', class_='dd')
但如果说我们的目标不是所有的 li 下面的 a 标签,而是部分 class="*" 的 li 下面的 a 标签,这时候我们就只能选择使用 xpath 来达到目的,当然如果你喜欢写遍历,觉得这样写出来逻辑展示更清晰,那你可以跳过这一节。
功能缺陷总结——xpath
model = etree.HTML(response.body_as_unicode())
model.xpath('//div[@class="box box-2 box-4"]')
model.xpath('//div[@class="box box-2 box-4 mt25"]')
model.xpath('//div[@class="box box-2 box-4 mt17"]')
来匹配目标,这可能要归结于 xpath 在设计的时候本身就是以类名的完全匹配来确定目标的,哪怕多一个空格:
model.xpath('//a[@class="dd"]')
文本获取
xpath 目标结点的 text 属性值对应的只是当前匹配元素下面的文本信息,如要获取该结点下面包括子结点在内的所有文本内容要使用 .xpath('string()') 的方式:
model = etree.HTML(response.body_as_unicode())
place = model.xpath('//div[@class="guide"]')
# nav and aiticle
if place:
mark = place[0].xpath('./span[@class="mark"]')
if mark:
# text = mark[0].text.strip().replace('\n','').replace('\r','') # false
text = mark[0].xpath('string()')
result['address'] = text
其他方面比较
关于爬虫中常见的两个网页解析工具的分析 —— lxml / xpath 与 bs4 / BeautifulSoup的更多相关文章
- 【XPath Helper:chrome爬虫网页解析工具 Chrome插件】XPath Helper:chrome爬虫网页解析工具 Chrome插件下载_教程_安装 - 开发者插件 - Chrome插件网
[XPath Helper:chrome爬虫网页解析工具 Chrome插件]XPath Helper:chrome爬虫网页解析工具 Chrome插件下载_教程_安装 - 开发者插件 - Chrome插 ...
- java基础71 XML解析中的【DOM和SAX解析工具】相关知识点(网页知识)
本文知识点(目录):本文下面的“实例及附录”全是DOM解析的相关内容 1.xml解析的含义 2.XML的解析方式 3.xml的解析工具 4.XML的解析原理 5.实例 6 ...
- css布局 - 工作中常见的两栏布局案例及分析
突然想到要整理这么一篇平时工作中相当常见但是我们又很忽视的布局的多种处理方法.临时就在我经常浏览的网站上抓的相对应的截图.(以后看到其他类型的我再补充) 既然截了图,咱们就直接看人家使用的布局方式,毕 ...
- MathType中常见的两种符号的运用
想要让公式编辑得快速又高效,MathType数学公式编辑器这个神助攻是少不了的.MathType是一款专用的数学公式编辑器,用它来编辑公式非常方便实用,并且排版也非常简单.下面介绍两种常见符号的应用. ...
- C++中常见的两种二义性问题及其解决方式
--------------------------------一.“倒三角”二义性问题------------------------------- 问题描述:卤煮之所以称之为“倒三角问题”,是因为 ...
- python接口测试中常见的两种接口依赖处理方式
一.请求体的字段依赖 这种情况多数是在当前测试的接口,它的前置接口的请求体中的字段要拿来在当前的接口请求体中继续使用,比如修改用户信息的接口,该接口会使用到用户名的字段,该字段是由创建用户时的请求体中 ...
- 留学Essay写作中常见的两类要求词盘点
写essay的时候,我们会常常因为各式各样的要求词而头疼:discuss,describing,evaluate,explain,等等,他们之间有何区别?如果你在思考这个问题,那么这篇文章就是为你写的 ...
- 简析--Java中常见的一些关键字的解析
在Java开发中我们经常会用到一些关键字,关键字的定义很有意思"Java事先定义好的,具有特殊含义的单词",那么我们怎么来用好关键字呢?下面我们对一些常见的关键字进行分析和比较; ...
- Python网络爬虫笔记(一):网页抓取方式和LXML示例
(一) 三种网页抓取方法 1. 正则表达式: 模块使用C语言编写,速度快,但是很脆弱,可能网页更新后就不能用了. 2. Beautiful Soup 模块使用Python编写,速度慢. ...
随机推荐
- 什么是XML?
XML被设计用来传输和存储数据. HTML被设计用来显示数据. 什么是XML? XML指可扩展标记语言(EXtensible Markup Language) XML是一种标记语言,很类似HTML X ...
- 源码安装 odoo12 -- 问题记录
odoo12启动过程中遇到的问题,及解决办法:1.ImportError: No module named ‘win32service’pipenv install pypiwin32 2.Impor ...
- Django 跨域请求 解决 axios 未完待续
import django import os # os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled5. ...
- Spring Boot 整合mybatis 使用多数据源
本人想要实现一个项目里面多个数据库源连接,所以就尝试写一个demo,不多说,先贴结构,再贴代码,可以根据以下的顺序,直接copy解决问题. 首先,dao和resource下的mappers可以用myb ...
- springmvc mybatis shiro构建cms系统
开发语言: java.ios.android 部署平台: linux.window jdk版本:JDK1.7以上版本 开发工具: eclipse.idea等 服务器中间件:Tomcat 6.7.Jbo ...
- rabbitmq初学之连接测试
Login was refused using authentication mechanism PLAIN. 用户名或密码没有设置,或者错误
- Git的SSH-key生成、导入及使用
Git主要使用4种协议传输数据:本地协议,SSH协议,Git协议和HTTP/S协议. SSH协议是最为常用的一种,正式介绍SSH之前,简要说明一下其它协议. 本地协议(file://) 本地协议的优点 ...
- .NET Core 中使用GB2312编码报错的问题
错误描述 环境 dotnet 2.1.4 现象 当代码中使用 System.Text.Encoding.GetEncoding("GB2312") //或者 System.Text ...
- fcitx4.2.0自定义中文标点符号
+fcitx 定制标点 http://forum.ubuntu.com.cn/viewtopic.PHP?t=376701&p=2755636 下载punc.mb.gz放到~/.config/ ...
- PMP:2.项目运行环境
事业环境因素(EEF):事业环境因素源于项目外部(往往是企业外部)的环境,是指项目团队不能控制的,将对项目产生影响.限制或指令作用的各种条件. 组织内部的事业环境因素: { uu组织文化.结构 ...