python爬虫(中)--提取
前言
在python爬虫(上)–请求——关于旅游网站的酒店评论爬取(传参方法)和python爬虫(上)–请求——关于模拟浏览器方法中我们都在讲爬虫如何去做页面请求的问题,这一步的目的是拿到包含所有不管有没有异步加载的数据的页面源码(静态文本),爬虫最难的环节就在这么一段发生在http请求的过程上,可是并不是拿到这么一个包含一大堆标签,一大堆样式代码,一大堆有的没的数据就万事大吉了,我们要的并不是这么一个混乱的东西,我们要干干净净的目的数据,怎么做?提取(Extract)!
而Python中做提取这个步骤的一般是re,BeautifulSoup和lxml这三个模块
RE
RE是Regular Expression,也就是我们经常说的正则表达式,它是基于字符串格式匹配来完成提取的。 Python爬虫入门七之正则表达式,关于RE的用法这一篇博文已经讲得很全面了,我就不再赘述。而我要说明的是,其实RE的方法不用特地去记忆,用多几次就能熟练了自然就记住了,记不住的时候上网查查表就好了,关键是对于什么情况下该用怎样的正则表达式来匹配才是RE的难点,在这一点上是就算你把RE背的滚瓜烂熟如果缺少实践、思考和测试是不可能做的很好的
RE在python中:
re模块是python内置模块,所以不用另外用pip安装,直接import re即可
python下会将正则表达式转换为字节码,利用C语言匹配引擎进行匹配
re模块中常用而且要分清的三个方法:
- re模块中的match()只在字符串开始位置尝试匹配正则,也就是只报告从位置0开始的匹配情况
- 而search()函数式扫描整个字符串来查找匹配
- re.findall()在字符串中找到正则表达式所匹配的所有子串,并组成一个【List】返回
而python下的BeautifulSoup的模块,它也是基于RE,是用python写的,出了名的很好的容错性,之所以有很好容错性是和它的实现方式有关的,详细请看这篇Blog,里面提到“ BeautifulSoup, because it is known to have a very error resistant parser. ”
BeautifulSoup自己的正则提取的方法和python自带re模块中方法的写法差不多,要特别提醒的是,re中的是re.findall(),而BeautifulSoup中的是beautifulsoup.find_all(),写法上是有区别的.
还有BeautifulSoup是第三方库,不过在很多Linux distros,里面都会预安装有,不过那是系统级别的,不是pip安装的,如果需要最新版的还是得自己通过pip来安装
补充一些re匹配实例:
Q1:
s=’[lol]请删除这些markup清理掉[emoji],谢谢’
pattern=re.compile('\[.*?\]') #考察的是非贪婪模式
cleanup=pattern.sub('',s)
Xpath
Xpath=XML Path Language,针对XML(HTML是XML的子集所以也可以)格式的字符串基于数据位置来完成提取的:
①可以在XML中查找信息; ②支持HTML查找; ③通过元素,属性进行导航
选择Xpath的理由: Xpath对于现在越来越复杂的页面结构,特别是一大堆的div标签嵌套的情况下,是一个比RE更好的选择,而且像Chrome自带就有 ‘copy xpath’ 生成目的数据的xpath定位信息和FireFox 的Firebug工具也能很容易的生成Xpath,而且lxml模块是用C语言写的(libxml2+libxslt的原生C代码),执行效率会比beautifulsoup快很多.
在python中要使用Xpath可以from lxml import etree,然后把比方说具有HTML格式的文本a,用etree.HTML(a)打开放进b [b=etree.HTML(a)],然后 b.xpath(‘填入你的xpath’)
关于Xpath使用的友情提醒: “//”的这种匹配方式返回的是一个【List】
获取的Xpath的两个方法: ①使用以上等方法通过观察找规律的方式获取Xpath; ②使用Chrome网页中右击→审查元素→copy xpath;
RE和Xpath的对比
我有个习惯就是如果能做到同样工作的工具我都喜欢做一个横向对比,结合我在网上找了很久的评论分析和各种帖子还有我自己的使用体会。
- Xpath和jQuery对页面的解析都是基于XML的语义进行提取的(HTML是XML的子集当然也可以),而RE则的纯粹基于plain text;
- RE在对付简单的页面的解析提取上是没有问题的,但是如果页面复杂度较高的时候(比如一堆DIV来回嵌套),那么设计一个恰当的RE pattern可能远远比写一个xpath要复杂,特别是目前主流的基于CSS的页面设计方式,其中大部分关键节点都会有ID——对于使用jQuery的页面来说更是如此(从建站和网页技术角度来分析),此时Xpath就比 RE 有了决定性优势;
-
Xpath基本上是用一种类似于目录树的方法来描述在XML的路径(最难的问题是xpath对页面要求较高,必须是合格的XHTML/XML/HTML…);
“要求较高”的意思是: ①只能对付具备标准的目录树结构,而对付单纯无结构字符串是无能的; ②对付专门的东西还是要专门的工具更为高效;
- 而re只要在传入的东东是字符串格式就可以了,使用场景更为广泛
举个栗子:
<html>
<body>
<h1>
文本
</h1>
</body>
</html>
假设上面的文本为text 定位上面的”文本”这两个字,有两种办法: ①正则匹配,可以这么写:
pattern=re.compile(r'\W*')
zh=re.findall(pattern,text)
②Xpath,可以这么写:
selector=etree.HTML(text)
zh=selector.xpath('/html/body/h1/text()')
#或者zh=selector.xpath('//h1/text()')
示例
同样我也是改了手上的项目做一个示例:
#! /usr/bin/env python
#encoding:utf-8
from lxml import etree
def Extract(websourcode):
extracted_data_=[]
selector=etree.HTML(websourcode)
#print type(selector)--<type 'lxml.etree._Element'>
date=selector.xpath('xpath_to_locate_date')
spiderTime=time.ctime()#spiderTime是str
extracted_data.append(spiderTime)
date=str(date)
extracted_data.append(date)
print '共',len(extracted_data),'字段'
extracted_data_.append(extracted_data)
return etracted_data_
最后的extracted_data_是一个包含有多个list的list,知道这点在后面入库的时候很有用【executemany(sql,extracted_data_))】