Python 网络爬虫-正则表达式、BeautifulSoup、lxml三种提取方法

来源:互联网 发布:报刊制作软件coreldraw 编辑:程序博客网 时间:2024/06/05 11:52

正则表达式

1. Python Re模块

1. 数量词的贪婪模式与非贪婪模式

正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式”ab*”如果用于查找”abbbc”,将找到”abbb”。而如果使用非贪婪的数量词”ab*?”,将找到”a”。

注:我们一般使用非贪婪模式来提取。

2. 反斜杠问题

与大多数编程语言相同,正则表达式里使用”\”作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符”\”,那么使用编程语言表示的正则表达式里将需要4个反斜杠”\\”:前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r”\”表示。同样,匹配一个数字的”\d”可以写成r”\d”。有了原生字符串,妈妈也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

Python 自带了re模块,它提供了对正则表达式的支持。主要用到的方法列举如下:
这里写图片描述
Pattern : 可以理解为一个匹配模式;
Pattern = re.compile(r’hello’)
通过compile方法编译生成一个pattern对象
其中flag是匹配模式,取值可以使用按位或运算‘|’表示同时生效,比如re.I|re.M
这里写图片描述

  1. re.match(pattern,string[,flags])
    作用:从string的开头开始,尝试匹配pattern,一直向后匹配,如果遇到无法匹配的字符,立即返回None,如果匹配未结束已经到达string的末尾,也会返回None。两个结果均表示匹配失败,否则匹配pattern成功,同时匹配终止,不再对string向后匹配。下面我们通过一个例子理解一下
    这里写图片描述
  2. re.search(pattern,string[,flags])
    search方法与match方法极其类似,区别在于match()函数只检测re是不是在string的开始位置匹配,search()会扫描整个string查找匹配,match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回None。同样,search方法的返回对象同样match()返回对象的方法和属性。我们用一个例子感受一下
    这里写图片描述

  3. re.split(pattern,string[,maxsplit])
    按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。我们通过下面的例子感受一下。
    这里写图片描述

  4. re.findall(pattern,string[,flags])
    搜索string,以列表形式返回全部能匹配的字串。我们通过这个例子来感受一下
    这里写图片描述

  5. re.finditer(pattern,string[,flags])
    搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。我们通过下面的例子来感受一下
    这里写图片描述
  6. re.sub(pattern,repl,string[,count])
    使用repl替换string中每一个匹配的子串后返回替换后的字符串。
    当repl是一个字符串时,可以使用\id或\g、\g引用分组,但不能使用编号0。
    当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
    count用于指定最多替换次数,不指定时全部替换。
    这里写图片描述
  7. re.subn(pattern,repl,string[,count])

2. Python 提取网站的正则表达式规则

1).*? 是一个固定的搭配,.和*代表可以匹配任意无限多个字符,加上?表示使用非贪婪模式进行匹配,也就是我们会尽可能短地做匹配,以后我们还会大量用到 .*? 的搭配。

2)(.*?)代表一个分组,在这个正则表达式中我们匹配了五个分组,在后面的遍历item中,item[0]就代表第一个(.*?)所指代的内容,item[1]就代表第二个(.*?)所指代的内容,以此类推。

正则表达式的语法规则

取自网上
该图片取自网上

实例代码

# _*_ encoding:utf8 _*_import repattern = re.compile(r'<a.*?href=.*?<\/a>',re.I|re.S|re.M)#构建一个patternpattern1 = re.compile(r'<td>.*?</td>',re.I|re.S|re.M)res_url = r"(?<=href=\").*?(?=\")|(?<=href=\').*?(?=\')"pattern2 = re.compile(res_url)content = """<td> <a href="https://www.baidu.com/articles/zj.html" title="浙江省">浙江省主题介绍</a> <a href='https://www.baidu.com//articles/gz.html' title="贵州省">贵州省主题介绍</a> </td> """result = re.findall(pattern2,content) #找出所有满足正则表达式的内容for i in result:    print i

BeautifulSoup

安装

pip install beautifulsoup4

内容

解析器 使用方法 优点 安装库及缺点 Python标准库 BeautifulSoup(marup,’html.parser’) 1.容错率高
2.速度适中 Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 lxml HTML解析器 BeautifulSoup(marup,’lxml’) 1.速度快
2.容错率高 pip install lxml lxml XML解析器 BeautifulSoup(marup,[‘lxml’,’xml’])
BeautifulSoup(marup,’xml’) 1.速度快
2.唯一支持XML的解析器 pip install lxml html5lib解析器 BeautifulSoup(marup,’html5lib’) 1.容错率最好
2.以浏览器的方式解析文档
3.生成HTML5格式的文档 速度慢

实例代码

# _*_ encoding:utf8 _*_import urllib2import urllibfrom bs4 import BeautifulSoupimport reurl = "http://www.baidu.com"user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'headers = { 'User-Agent' : user_agent }try:    request = urllib2.Request(url,headers=headers)    #创建一个请求对象    response  = urllib2.urlopen(request)    #生成一个响应对象    content = response.read()    #读取html的内容    html = BeautifulSoup(content,'html.parser')    #以html.parser HTML解析器 格式化为BeautifulSoup    for t in  html.find_all('a',limit=20):        print t['href'] #取出每一条中的href属性值            for t in  html.find_all('a',limit=20):    print t.text #取出标签a的内容    for t in  html.find_all('a',class_='bri',limit=20):  #遇到class这种与Python calss类冲突的属性在后面加下划线 class_    print t #取出标签a的内容for t in  html.find_all('a',wdfield="word",limit=20):    print t #取出标签a的内容for t in  html.find_all(attrs={"wdfield":"word"}): #满足属性所有标签    print t #取出标签a的内容  except urllib2.URLError as e:    pass

lxml

安装

pip install lxml

内容

利用pip安装就可以,如果遇到安装失败就多装几次。

表达式 描述 实例 实例描述 / 从根节点选取 /html/head 选取head下的所有节点 // 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 //a 选取内容中所有的标签a . 选取当前节点 //a/. 选取标签a的节点 .. 选取当前节点的父节点 /html/body/a/.. 选取标签a的父节点的所有节点,实例就是body所有子节点 @ 选取属性 /html/body/a/@href 选取标签a中href属性 * 匹配任何节点 //* 匹配任何的节点 @* 匹配任何属性节点 //a/@* 找出标签a中所有的属性节点 | 计算多个节点集 //a|//body|//head 找出所有标签a、标签body、标签head

实例代码

# _*_ encoding:utf8 _*_import reimport urllibimport urllib2from lxml import etreecontent = """<html>  <head>    <meta name="content-type" content="text/html; charset=utf-8" />    <title>友情链接查询 - 站长工具</title>    <!-- uRj0Ak8VLEPhjWhg3m9z4EjXJwc -->    <meta name="Keywords" content="友情链接查询" />    <meta name="Description" content="友情链接查询" />  </head>  <body>    <h1 class="heading">Top News</h1>    <p style="font-size: 200%">World News only on this page</p>    Ah, and here's some more text, by the way.    <p>... and this is a parsed fragment ...</p>    <a href="http://www.cydf.org.cn/" rel="nofollow" target="_blank1">青少年发展基金会</a>     <a href="http://www.4399.com/flash/32979.htm" target="_blank">洛克王国</a>     <a href="http://www.4399.com/flash/35538.htm" target="_blank">奥拉星</a>     <a href="http://game.3533.com/game/" target="_blank">手机游戏</a>    <a href="http://game.3533.com/tupian/" target="_blank">手机壁纸</a>    <a href="http://www.4399.com/" target="_blank">4399小游戏</a>     <a href="http://www.91wan.com/" target="_blank">91wan游戏</a>  </body></html>"""############读取网址来获取html内容#url = "http://www.baidu.com/"#url请求路径#user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'#headers = { 'User-Agent' : user_agent }#request = urllib2.Request(url,headers=headers)#request实例化一个请求对象#response = urllib2.urlopen(request)#response实例化一个响应对象#content = response.read().decode('utf-8')#############try:    html = etree.HTML(content.decode('utf-8'))    # html = etree.parse('hello.html') #利用parse来读取文件    #转化为lxml格式    result1 = html.xpath(u'//a')   # //a查询节点为a 不管位置在哪里    for res in result1:        print etree.tostring(res)  # 打印查询的结果    result2 = html.xpath(u'/html/body/h1')        for res in result2:        print etree.tostring(res)    result3 = html.xpath(u'//*')   # //* 所有的内容    for res in result3:        print etree.tostring(res)    result4 = html.xpath(u"//a[@target='_blank1']")#查询所有的<a>标签中target='_blank1'的内容    for res in result4:        print etree.tostring(res)    result5 = html.xpath(u"//a[last()]")#查询所有的<a>标签中最后一个的内容    for res in result5:        print etree.tostring(res)     result6 = html.xpath(u"//a")#    for res in result6:        print res.text    #打印标签包含的内容    result7 = html.xpath(u'//a[@target="_blank1"]/@href')   #找出标签a中属性为href的内容    for res in result7:        print res       result7 = html.xpath(u'//*[@target="_blank"]/@href')   #找出标签属性为target="_blank"中href的内容    for res in result7:        print res         result8 = html.xpath(u'//a|//h1')   #找出所有的标签a或者前边h1    for res in result8:        print   etree.tostring(res)    result9 = html.xpath(u'//*[@*]')  #找出所有带有属性的标签    for res in result9:        print etree.tostring(res)except urllib2.URLError as e:    print e

结语

通过lxml获取信息的关键在于xpath的运用,多练习xpath的路径的写法,自然能熟能生巧!
正则表达式效率是最高的,缺点在于表达式比较繁琐!
lxml的效率比beautifulsoup要高很多,而且比beautifulsoup更加的灵活!
我也是刚学,只是当过笔记记下来,希望能帮到需要的人,有错误的地方还望指正!

阅读全文
0 0
原创粉丝点击