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

正则表达式

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 re
pattern = re.compile(r'<a.*?href=.*?<\/a>',re.I|re.S|re.M)#构建一个pattern
pattern1 = 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 urllib2
import urllib
from bs4 import BeautifulSoup
import re
url = "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 re
import urllib
import urllib2
from lxml import etree
content = """
<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更加的灵活!
我也是刚学,只是当过笔记记下来,希望能帮到需要的人,有错误的地方还望指正!

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FlyingO123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值