正则表达式
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
- re.match(pattern,string[,flags])
作用:从string的开头开始,尝试匹配pattern,一直向后匹配,如果遇到无法匹配的字符,立即返回None,如果匹配未结束已经到达string的末尾,也会返回None。两个结果均表示匹配失败,否则匹配pattern成功,同时匹配终止,不再对string向后匹配。下面我们通过一个例子理解一下
re.search(pattern,string[,flags])
search方法与match方法极其类似,区别在于match()函数只检测re是不是在string的开始位置匹配,search()会扫描整个string查找匹配,match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回None。同样,search方法的返回对象同样match()返回对象的方法和属性。我们用一个例子感受一下
re.split(pattern,string[,maxsplit])
按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。我们通过下面的例子感受一下。
re.findall(pattern,string[,flags])
搜索string,以列表形式返回全部能匹配的字串。我们通过这个例子来感受一下
- re.finditer(pattern,string[,flags])
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。我们通过下面的例子来感受一下
- re.sub(pattern,repl,string[,count])
使用repl替换string中每一个匹配的子串后返回替换后的字符串。
当repl是一个字符串时,可以使用\id或\g、\g引用分组,但不能使用编号0。
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
count用于指定最多替换次数,不指定时全部替换。
- 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更加的灵活!
我也是刚学,只是当过笔记记下来,希望能帮到需要的人,有错误的地方还望指正!