文章目录
- 使用urllib库
- 使用request模块发送请求
- 1.使用urlopen()
- urlopen - data参数
- urlopen - timeout参数
- 2. Request()
- 3.高级用法
-
- 使用error模块处理异常
-
- 使用parse模块解析链接
- 1. urlparse()
- 2. urlunparse()
- 3. urlsplit()
- 4. urlunsplit()
- 5. urljoin()
- 6. urlencode()
- 7. parse_qs()
- 8. quote()
- 9. unquote()
- 使用requests库
- 基本用法
- GET请求
-
- POST请求
- 高级用法
- 1. 文件上传
- 2. cookie
- 3.会话维持
- 4. SSL证书验证
- 5. 代理设置
- 6. 超时验证
- 7. 身份认证
- 8. Prepared Request
- 正则表达式
- 1. match()
-
- 2. search()
- 3. findall()
-
使用urllib库
在Python2中,有urllib和urllib2两个库来实现请求的发送。而在python3中,已经不存在urllib这个库了,统一为urllib。
首先来了解一下urllib库,它是Python内置的http请求库,所以不需要任何额外安装即可使用。它包含如下四个模块:
- request:它是最基本的http请求模块,可以用于模拟发送请求。
- error:异常处理模块,如果出现请求错误,我们可以捕获这些异常。
- parse:一个工具模块,提供了许多url处理方法,比如拆分,解析,合并等。
- robotparse:主要用于识别网站的robot.txt文件,然后判断哪些网站可以爬,哪些网站不可以爬。
使用request模块发送请求
1.使用urlopen()
urllib.request.urlopen(url, data=None, [ timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
import urllib.request
response = urllib.request.urlopen('https://www.python.org')
print(type(response))
可见,response是一个HTTPResponse类型的对象,其主要包括read(),readinto(),getheader(name),getheaders(),fileno()等方法,以及msg,version,reason,debuglevel,closed等属性。
调用read()方法可以得到目标网址的网页源码,查看status属性可以得到网站返回结果中的状态码。
import urllib.request
response = urllib.request.urlopen('https://www.python.org')
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))
urlopen - data参数
data 参数是可选的,如果传递了这个参数,则请求方式就变成了POST方式。data参数必须是字节流类型的。
网站httpbin.org能将我们的请求字段再回给我们。
import urllib.request
import urllib.parse
data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post', data=data)
print(response.read())
可见,上述请求中的data数据放在了form字段中,这表明我们现在模拟的是以POST方式传输数据的表单提交方式。
urlopen - timeout参数
timeout 参数用于设置超时时间,单位为秒。如果请求超出了设置的这个时间,还没有得到响应,那么就会抛出异常。如果不指定此参数,就使用全局默认时间。它支持HTTP , HTTPS 、FTP请求。
import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get', timeout=1)
print(response.read())
由于由于请求超时会抛出异常,因此我们可以对上述代码添加异常排查:
import urllib.request
import urllib.error
import socket
try:
response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout):
print('TIME OUT')
2. Request()
如果需要在请求头中添加参数,则需要Request()来构建。
import urllib.request
request = urllib.request.Request('https://python.org')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
Request的构造方法:
下面来看一个详细的使用Request()的例子:
from urllib import request, parse
url = 'http://httpbin.org/post'
headers = {
'User-Agent': 'Mozilla/4.0(compatible; MSIE 5.5; Windows NT)',
'Host':'httpbin.org'
}
dict = {
'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
另外,请求头除了可以直接定义外,还可以使用req的add_header()方法:
req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0(compatible; MSIE 5.5; Windows NT)')
req.add_header('Host','httpbin.org')
3.高级用法
在上面的使用中,虽然可以构造请求,但是对于一些更高级的操作(比如Cookies 处理、代理设置等),就需要更强大的工具Handler登场了。简而言之,我们可以把它理解为各种处理器,有专门处理登录验证的,有处理Cookies的,有处理代理设置的。利用它们,我们几乎可以做到HTTP请求中所有的事情。
首先,介绍一下urllib.request模块中的BaseHandler类,它是所有其他Handler的父类,它提供了最基本的方法,例如default_open()、protocol_request()等。
再来看看BaseHandleer的子类:
- HTTPDefaultErrorHandler:用于处理HTTP 响应错误,错误都会抛出HTTP Error 类型的异常。
- HTTPRedirectHandler:用于处理重定向。
- HTTPCookieProcessor: 用于处理Cookies 。
- ProxyHandler:用于设置代理,默认代理为空。
- HπPPasswordMgr:用于管理密码,它维护了用户名和密码的表。
- HTTPBasicAuthHandler:用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题。
另外一个比较重要的类就是OpenerDirector,我们可以称之为Opener,之前用过的urlopen()实际上也属于Opener,它是一个urllib提供给我们的封装好了的Opener。
那么,为什么要引人Opener呢?因为需要实现更高级的功能。之前使用的Request和urlopen()相当于类库为你封装好了极其常用的请求方法,利用它们可以完成基本的请求,但是现在不一样了,我们需要实现更高级的功能,所以需要深入一层进行配置,使用更底层的实例来完成操作,所以这里就用到了Opener 。
使用Opener需要用到open()方法,返回的类型和urlopen()如出一辙,那么,它和Handler 有什么关系呢?简而言之,就是利用Handler来构建Opener 。
验证
对于需要账户验证才能登陆查看网页来说,需要使用Handler构建opener来进行模拟验证。
from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError
username = '程一夕'
password = '#importali'
url = 'https://account.aliyun.com/login/login.htm?oauth_callback=http%3A%2F%2Fdns.console.aliyun.com%2F#/dns/setting/baibainote.pro'
p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)
try:
result = opener.open(url)
html = result.read().decode('utf-8')
result = opener.open(url)
print(html)
except URLError as e:
print(e.reason)
代理
from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener
proxy_handler = ProxyHandler({
'http': '127.0.0.1:12308'
})
opener = build_opener(proxy_handler)
try:
response = opener.open('https://www.baidu.com')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
Cookies
可通过下面的方式来获取一个网站的cookie:
import http.cookiejar, urllib.request
cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
print(item.name + "=" + item.value)
上述输出:
BAIDUID=D450CE81692242D57AF5680E33E6F545:FG=1
BIDUPSID=D450CE81692242D57AF5680E33E6F545
H_PS_PSSID=1423_21104_28328_28131_28267_22073
PSTM=1547712883
delPer=0
BDSVRTM=0
BD_HOME=0
将cookie保存为Mozila的文件形式,可以使用如下代码:
import http.cookiejar, urllib.request
cookie = http.cookiejar.MozillaCookieJar('cookies.txt')
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)
这里的cookies.txt文件内容为:
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.
.baidu.com TRUE / FALSE 3695196365 BAIDUID 3941F31A3424DAB2A92D7F2AA1696281:FG=1
.baidu.com TRUE / FALSE 3695196365 BIDUPSID 3941F31A3424DAB2A92D7F2AA1696281
.baidu.com TRUE / FALSE H_PS_PSSID 1454_21093_28329_28131_28267
.baidu.com TRUE / FALSE 3695196365 PSTM 1547712718
.baidu.com TRUE / FALSE delPer 0
www.baidu.com FALSE / FALSE BDSVRTM 0
www.baidu.com FALSE / FALSE BD_HOME 0
当然了,也可以改为LWP格式的cookie:
cookie = http.cookiejar.LWPCookieJar('cookies.txt')
此时,cookies.txt文件的内容就变为:
#LWP-Cookies-2.0
Set-Cookie3: BAIDUID="DC98555BA602B4179B60D70967807CE0:FG=1"; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-02-04 11:34:32Z"; version=0
Set-Cookie3: BIDUPSID=DC98555BA602B4179B60D70967807CE0; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-02-04 11:34:32Z"; version=0
Set-Cookie3: H_PS_PSSID=1442_21125_18559_28329_28132_28267; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: PSTM=1547713226; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-02-04 11:34:32Z"; version=0
Set-Cookie3: delPer=0; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: BDSVRTM=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
Set-Cookie3: BD_HOME=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
得到了LWP格式的cookie后,我们就可以从cookies.txt文件中读内容:
import http.cookiejar, urllib.request
cookie = http.cookiejar.LWPCookieJar()
cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))
上述代码运行正常的话,则会输出百度首页的源码。
使用error模块处理异常
1. URLError
URLError 类来自urllib库的error 模块,它继承自OSError类,是error 异常模块的基类,由request模块产生的异常都可以通过捕获这个类来处理。
from urllib import request, error
try:
response = request.urlopen('https://www.baidu.com')
except error.URLError as e:
print(e.reason)
2. HTTPError
它是URLError的子类,专门用来处理HTTP请求错误,比如认证请求失败等。它有如下3 个属性:
- code: 返回HTTP 状态码,比如404 表示网页不存在, 500 表示服务器内部错误等。
- reason: 同父类一样,用于返回错误的原因。
- headers: 返回请求头
from urllib import request, error
try:
response = request.urlopen('https://cuiqingcai.com/index.html')
except error.HTTPError as e:
print(e.reason, e.headers)
由于HTTPError是URLError的子类,于是可以先捕获子类的异常再捕获父类的异常:
from urllib import request, error
try:
response = request.urlopen('https://cuiqingcai.com/index.html')
except error.HTTPError as e:
print(e.reason, e.code, e.headers)
except error.URLError as e:
print(e.reason)
else:
print('Request.successfully')
使用parse模块解析链接
urllib 库里还提供了parse模块,它定义了URL处理的标准接口,例如实现URL 各部分的抽取、合并以及链接转换。它支持如下协议的URL 处理:file 、ftp 、gopher等。
1. urlparse()
urlparse()定义:
urlparse(urlstring, scheme, allow_fragments)
from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#coment')
print(type(result), result)
标准URL格式:scheme://netloc/path;params?query#fragment
- scheme:协议(😕/前面)
- netloc:域名(第一个/符号前面)
- path:访问路径(域名后面)
- params:参数
- query:查询条件(?问号后面,一般用作GET类型的URL)
- fragment:锚点(#号后面)
2. urlunparse()
有了urlparse(),相应地就有了它的对立方法urlunparse()。它接受的参数是一个可迭代对象,但是它的长度必须是6,否则会抛出参数数量不足或者过多的异常。
from urllib.parse import urlunparse
data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))
3. urlsplit()
from urllib.parse import urlsplit
result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment')
print(result)
print(result.scheme)
print(result[0])
4. urlunsplit()
与urlunparse()类似,它也是将链接各个部分组合成完整链接的方法,传人的参数也是一个可迭代对象,例如列表、元组等,唯一的区别是长度必须为5 。
from urllib.parse import urlunsplit
data = ['http', 'www.baidu.com', 'index.html', 'a=6', 'comment']
print(urlunsplit(data))
5. urljoin()
有了urlunparse()和urlunsplit()方法,我们可以完成链接的合井,不过前提是必须要有特定长度的对象,且链接的每一部分都要清晰分开。
此外,我们还有另一个便捷的方法,那就是urljoin()方法。我们可以提供一个base_url 作为第一个参数,将新的链接作为第二个参数,该方法会分析base_url中的scheme 、netloc 和path这3个内容并对新链接缺失的部分进行补充,最后返回结果。
from urllib.parse import urljoin
print(urljoin('http://www.baidu.com', 'FAQ.html'))
print(urljoin('http://www.baidu.com ', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about. html', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://cuiqingcai.com/index.php'))
print(urljoin ('http://www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com#comment', '?category=2'))
可以发现,base_url提供了三项内容scheme,netloc和path。如果这3项在新的链接里不存在,就予以补充;如果新的链接存在,就使用新的链接的部分。而base_url中的params、query和fragment就不起作用了。
6. urlencode()
from urllib.parse import urlencode
params = {
'name': 'germey',
'age': 22
}
base_url = 'http://www.baidu.com'
url = base_url + urlencode(params)
print(url)
7. parse_qs()
有了序列化,必然就有反序列化。如果我们有一串GET请求参数,利用parse_qs()方法,就可以将它转回字典。
from urllib.parse import parse_qs
query = 'name=germey&age=22'
print(parse_qs(query))
8. quote()
该方法可以将内容转化为URL编码的格式。URL中带有中文参数时,有时可能会导致乱码的问题,此时用这个方法可以将中文字符转化为URL编码。
from urllib.parse import quote
keyword = '壁纸'
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)
9. unquote()
有了quote()方法,反之当然就有unquote()方法,它可以进行URL解码:
from urllib.parse import unquote
url = 'https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8'
print(unquote(url))
使用requests库
虽然urllib库似乎无所不能,但其中确实有不方便的地方,比如处理网页验证和Cookies时,需要写Opener和Handler来处理,很显然,这两者的构建有点麻烦。为了更加方便地实现这些操作,就需要用到更为强大的库requests,有了它Cookies、登录验证和代理设置等操作都变得额外简单。
基本用法
import requests
req = requests.get('https://www.baidu.com')
print(type(req))
print(req.status_code)
print(type(req.text))
print(req.cookies)
requests库的get()方法可以完成一个GET请求,但更令人激动的是,其它请求类型在requests中依然只需要一句话来完成:
r = requests.post('http:/httpbin.org/post')
r = requests.put('http://httpbin.org/put')
r = requests.delete('http://httpbin.org/delete')
r = requests.head('http://httpbin.org/get')
r = requests.options('http://httpbin.org/get')
GET请求
要想在GET请求中附加其它参数,也可以用字典类型来构建:
import requests
data = {
'name': 'germey',
'age': 22
}
r = requests.get('http://httpbin.org/get', params=data)
print(r.text)
抓取网页
我们试着抓取一个真正的网页,注意要改游览器标识,否则知乎会禁止抓取。
import requests
import re
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
r = requests.get('https://www.zhihu.com/explore', headers=headers)
pattern = re.compile('explore-feed.*?question_link.*?>(.*?)</a>', re.S)
titles = re.findall(pattern, r.text)
print(titles)
抓取二进制数据 | 图片,视频
上面我们爬取的都是文本格式的数据(网页源码),但实际网页上其实有很多图片,视频,音乐等,要想抓取它们,就必须拿到它们的二进制数据。
import requests
r = requests.get('https://github.com/favicon.ico')
with open('favicon.ico', 'wb') as f:
f.write(r.content)
响应
发送请求后,得到的自然就是响应。在上面的实例中,我们使用text和content 获取了响应的内容。此外,还有很多属性和方法可以用来获取响应中的其他信息,比如状态码、响应头、Cookies 等。
import requests
r = requests.get('https://www.jianshu.com')
print(type(r.status_code), r.status_code)
print(type(r.headers), r.headers)
print(type(r.cookies), r.cookies)
print(type(r.url), r.url)
print(type(r.history), r.history)
状态码一般用于判断请求是否发送成功。为了更方便的使用状态码,requests库中封装了一个内置的查询对象requests.codes。
import requests
r = requests.get('https://www.jianshu.com')
exit() if not r.status_code == requests.codes.ok else print('Request Successfully')
POST请求
import requests
data = {'name': 'germey', 'age': 22}
r = requests.post("http://httpbin.org/post", data=data)
print(r.text)
高级用法
1. 文件上传
import requests
files = {'file': open('favicon.ico', 'rb')}
r = requests.post("http://httpbin.org/post", files=files)
print(r.text)
import requests
files = {'file': open('favicon.ico', 'rb')}
r = requests.post("http://httpbin.org/post", files=files)
print(r.text)
2. cookie
前面说的urllib库也可以处理cookie,但相对比较复杂,而有了requests,获取和设置Cookies 只需一步即可完成。
import requests
r = requests.get('https://www.baidu.com')
print(r.cookies)
for key, value in r.cookies.items():
print(key + '=' + value)
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
BDORZ=27315
3.会话维持
在requests中,如果直接利用get()或post()等方法的确可以做到模拟网页的请求,但是这实际上是相当于不同的会话,也就是说相当于你用了两个浏览器打开了不同的页面。
设想这样一个场景,第一次请求利用post()方法登录了某个网站,第二次想获取成功登录后的自己的个人信息,你又用了一次get()方法去请求个人信息页面。实际上,这相当于打开了两个浏览器,这是两个完全不相关的会话,这样其实是不能获取到个人信息的。
当然,如果在两次请求时设置一样的cookies也的确可以做到维持会话的效果,但这显得略微繁琐。我们可以引入另一个利器——Session对象。
先看看连续发生两次GET请求能否获取cookie:
import requests
requests.get('http://httpbin.org/cookies/set/number/123456789')
r = requests.get('http://httpbin.org/cookies')
print(r.text)
再使用Session对象试试:
import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)
4. SSL证书验证
requests 还提供了证书验证的功能。当发送HTTP 请求的时候,它会检查SSL 证书,我们可以使用verify参数控制是否检查此证书。其实如果不加verify参数的话,默认是True ,会自动验证。
import requests
response = requests.get('https://www.12306.cn', verify=False)
print(response.status_code)
如果请求一个HTTPS 站点,但是证书验证错误时,就会报错,把verify 参数设置为False可以跳过SSL证书验证,避免产生这样的错误。
5. 代理设置
对于某些网站,在测试的时候请求几次,能正常获取内容。但是一旦开始大规模爬取,对于大规模且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面, 更甚者可能会直接封禁客户端的IP,导致一定时间段内无法访问。这可以通过设置代理来解决。
import requests
proxies = {
"http": "http://127.0.0.1:12308"
}
r = requests.get('https://www.taobao.com', proxies=proxies)
print(r.text)
6. 超时验证
在本机网络状况不好或者服务器网络响应太慢甚至无响应时,我们可能会等待特别久的时间才可能收到响应,甚至到最后收不到响应而报错。为了防止服务器不能及时响应,应该设置一个超时时间,即超过了这个时间还没有得到响应,那就报错。这需要用到timeout 参数。这个时间的计算是发送请求到服务器返回响应的时间。
import requests
r = requests.get('https://www.taobao.com', timeout=(10, 5))
print(r.status_code)
7. 身份认证
如果网站需要登录验证用户身份才能获取到相应网页,这就需要使用requests.auth模块提供的身份认证功能。
import requests
from requests.auth import HTTPBasicAuth
username = '程一夕'
password = '#importali'
url = 'https://account.aliyun.com/login/login.htm?oauth_callback=http%3A%2F%2Fdns.console.aliyun.com%2F#/dns/setting/baibainote.pro'
r = requests.get(url, auth=HTTPBasicAuth('username', 'password'))
print(r.status_code)
print(r.text)
8. Prepared Request
前面我们使用urllib库时用到了一个request对象来将要发送的请求信息,请求头等封装在一起,这在requests库中叫做Prepared Request,即将要发送的请求信息包。
from requests import Request, Session
url = 'http://httpbin.org/post'
data = {
'name': 'Germay'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
s = Session()
req = Request('POST', url, data=data, headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)
正则表达式
正则表达式不是Python 独有的,它也可以用在其他编程语言中。但是Python 的re 库提供了对整个正则表达式的实现,利用这个库,可以在Python中使用正则表达式。在Python 中写正则表达式几乎都要用到这个库,
1. match()
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}', content)
print(result)
print(result.group())
print(result.span())
提取分组中的内容
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld', content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())
贪婪和非贪婪
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$', content)
print(result)
print(result.group(1))
上述取出分组结果时,我们可以看到,本来我们的期望是匹配1234567这几个数字的,但匹配结果却显示只有7这一个数字,这就是贪婪模式的效果(默认)。
也就是说,(\d+)前面的.*将前面6个数字匹配完了(尽可能多的匹配),这6个数字其实并没有进入分组内。
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$', content)
print(result)
print(result.group(1))
给.*后加上?号后,就使得.*的匹配进入非贪婪模式,当.*匹配到Hello后面的那个空格时,由于后面的(\d+)恰好可以匹配接下来的7个数字,所有.*就不继续匹配了。
当非贪婪模式的匹配在模式字符串的末尾时会匹配不到任何字符:
import re
content = 'http://weibo.com/comment/kEraCN'
result = re.match('http.*?comment/(.*?)', content)
result2 = re.match('http.*?comment/(.*)', content)
print('result', result.group(1))
print('result2', result2.group(1))
修饰符
同样是上面用到过的字符串,给This之后加了换行符后,运行后会发现匹配失败。
import re
content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('He.*?(\d+).*?Demo$', content)
print(result.group(1))
这是因为, . 不能匹配换行符,这里只需加一个修饰符re.S, 即可修正这个错误:
result = re.match('He.*?(\d+).*?Demo$', content, re.S)
这个re.S修饰符很有用,因为HTML节点内经常会有换行,加上它,就可以匹配节点与节点之间的换行了。
下面还有一些修饰符,可以在需要的情况下使用:
修饰符 | 描述 |
---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别匹配 |
re.M | 多行匹配,影响^和$ |
re.S | 使.匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响\w,\W,\b和\B |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更加易于理解 |
2. search()
match()方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败了。
如下,由于模式字符串开头并不和目标字符串开头匹配,所以匹配直接失败
import re
content = 'Hello 1234567 World_Thisis a Regex Demo'
result = re.match('(\d+).*?Demo$', content)
print(result)
search()从前往后搜索,返回第一个匹配成功的子串:
import re
content = 'Hello 1234567 World_Thisis a Regex Demo'
result = re.search('(\d+).*?Demo$', content)
print(result)
print(result.group())
3. findall()
虽然search()可以返回匹配到的第一个子串,但如果想返回多个匹配成功的子串,那么可以使用findall()方法。
import re
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">经典老歌列表</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href ="/3.mp3 ” singer="齐泰">往事随风</a>
</li>
<li data-view ="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
results = re.findall('<li.*?href="(.*?)".*?singer="(.*)">(.*?)</a>', html, re.S)
print(results)
print(type(results))
for result in results:
print(result)
print(result[0], result[1], result[2])
4. sub()
除了使用正则表达式提取信息外,有时候还需要借助它来修改文本。比如,想要把一串文本中的所有数字都去掉,如果只用字符串的replace()方法,那就太烦琐了,这时可以借助sub()方法。
import re
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">经典老歌列表</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href ="/3.mp3 ” singer="齐泰">往事随风</a>
</li>
<li data-view ="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
html = re.sub('<a.*?>|</a>', '', html)
print(html)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
for result in results:
print(result.strip())
5. complie()
complie()可以将可以将正则表达式编译为正则表达式对象,以重复利用模式字符串。
import re
content1 = '2016-12-15 12:00'
content2 = '2016-12-17 12:55'
content3 = '2016-12-22 13:21'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
print(result1, result2, result3)
事实上,complie()中也可以传入re.S等修饰符,这样match()和search()中使用正则表达式就不用重复添加修饰符了。这也可以看出,complie()实际上是对正则表达式本身做了一层封装。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)