Python网络爬虫与信息提取——正则表达式
正则表达式的语法
正则表达式的常用操作符 |
||
操作符 | 说明 | 实例 |
. |
表示任何单个字符 |
|
[] |
字符集,对单个字符给出取值范围 | [abc]表示a、 b、c, [a-z]表示a到z单个字符 |
[^ ] | 非字符集,对单个字符给出排除范围 | [^ abc]表示非a或b或c的单个字符 |
* |
前一个字符0次或无限次扩展 | abc*表示ab、abc、abcc、 abccc等 |
+ |
前一个字符1次或无限次扩展 | abc+表示abc、abcc、 abccc等 |
? |
前一个字符0次或1次扩展 | abc?表示ab、abc |
| |
左右表达式任意一个 |
abc|def表示abc、def |
{m} | 扩展前一个字符m次 | ab{2}c表示abbc |
{m,n} | 扩展前一个字符m至n次(含n) |
ab{1,2}c表示abc、 abbc |
^ |
匹配字符串开头 | ^abc表示abc且在一 个字符串的开头 |
$ |
匹配字符串结尾 | abc$表示abc且在一个 字符串的结尾 |
() |
分组标记,内部只能使用|操作符 | (abc)表示abe, (abcldef)表示abe、 def |
\d |
数字,等价于[0-9] |
|
\w |
单词字符,等价于[A-Za-z0-9_] |
|
Re库的基本使用
raw string类型(原生字符串类型)
1.用原生字符串类型不用专义,如r'\d+\w{3}'
2.不用原生字符串类型,如‘\\d+\\w{3}’
Re库主要功能函数 |
|
函数 | 说明 |
re.search() | 在一个字符串中搜索匹配正则表达式的第一个位置, 返回match对象 |
re.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
re.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
re.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
re.finditer() | 搜索字符串,返回一个匹配结果的选代类型,每个迭代元素是match对象 |
re.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
1.re.search(pattern, string, flags=0)
在一个字符串中搜索匹配正则表达式的第一个 位置,返回match对象。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆flags:正则表达式使用时的控制标记
flags:正则表达式使用时的控制标记 | |
常用标记 | 说明 |
re.I re.IGNORECAS | 忽略正则表达式的大小写,[A-Z]能够匹配小写字符 |
re.M re.MULTILINE | 正则表达式中的^操作符能够将给定字符串的每行当作匹配开始 |
re.S re.DOTALL |
正则表达式中的操作符能够匹配所有字符,默认匹配除换行外的所有字符 |
import re
match = re.search(r'[1-9]\d{5}','bat 100081')
if match:
print match.group(0) ##100081
2.re. match(pattern, string, flags=0)
从一个字符串的开始位置起匹配正则表达式,返回match对象。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆flags: 正则表达式使用时的控制标记
import re
match = re.match(r'[1-9]\d{5}','bit 100081')
if match:
print match.group(0)
match = re.match(r'[1-9]\d{5}','100081 bit')
if match:
print match.group(0) #100081
3.re.findall(pattern, string, flags=0)
搜索字符串,以列表类型返回全部能匹配的子串。
◆pattern:正则表达式的字符串或原生字符串表示
◆string;待匹配字符串
◆flags:正则表达式使用时的控制标记
ls = re.findall(r'[1-9]\d{5}','bit100081 tsu100084')
print ls #['100081', '100084']
4.re.split(pattern, string, maxsplit=0, flags=0)
将一个字符串按照正则表达式匹配结果进行分割,返回列表类型。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆maxsplit:最大分割数,剩余部分作为最后一个 元素输出
◆flags:正则表达式使用时的控制标记
print re.split(r'[1-9]\d{5}','bit100081 tsu100084')
#['bit', ' tsu', '']
print re.split(r'[1-9]\d{5}','bit100081 tsu100084', maxsplit=1)
#['bit', ' tsu100084']
5.re.finditer(pattern, string, flags=0)
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆flags:正则表达式使用时的控制标记
for m in re.finditer(r'[1-9]\d{5}','bit100081 tsu100084'):
if m:
print m.group(0)
#100081
#100084
6.re.sub(pattern, repl, string, count=0, flags=0)
在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串。
◆pattern: 正则表达式的字符串或原生字符串表示
◆repl:替换匹配字符串的字符串
◆string:待匹配字符串
◆count:匹配的最大替换次数
◆flags:正则表达式使用时的控制标记
print re.sub(r'[1-9]\d{5}',':zipcode','bit100081 tsu100084')
#bit:zipcode tsu:zipcode
Re库的另一种等价用法:
pat = re.compile(r'[1-9]\d{5}')
res = pat.search('bit 100081')
regex = re.compile(pattern, flags=0)
将正则表达式的字符串形式编译成正则表达式对象
◆pattern:正则表达式的字符串或原生字符串表示
◆flags:正则表达式使用时的控制标记
Re库的match对象
match对象的属性 |
|
属性 | 说明 |
.string | 待匹配的文本 |
.re | 匹配时使用的pattern对象(正则表达式) |
.pos | 正则表达式搜索文本的开始位置 |
.endpos |
正则表达式搜索文本的结束位置 |
Match对象的方法 | |
方法 | 说明 |
.group(0) | 获得匹配后的字符串 |
.start() | 匹配字符串在原始字符串的开始位置 |
.end() | 匹配字符串在原始字符串的结束位置 |
.span() | 返回(.start(), .end()) |
m = re.search(r'[1-9]\d{5}','bit100081 tsu100084')
print m.string #bit100081 tsu100084
print m.re #<_sre.SRE_Pattern object at 0x10854d7b0>
print m.pos #0
print m.endpos #19
print m.group(0) #100081
print m.start() #3
print m.end() #9
print m.span() #(3,9)
实例:淘宝商品信息定向爬虫
def gethtmltext(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def parsepage(ilt, html):
try:
plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"', html)
tlt = re.findall(r'\"raw_title\"\:\".*?\"', html)
for i in range(len(plt)):
price = eval(plt[i].split(':')[1])
title = eval(tlt[i].split(':')[1])
ilt.append([price, title])
except:
print ""
def printgoodslist(ilt):
tplt = "{:4}\t{:8}\t{:16}"
print tplt.format("序号", "价格", "商品名称")
count = 0
for g in ilt:
print tplt.format(count, g[0], g[1])
def main():
goods = '书包'
depth = 2
start_url = 'https://s.taobao.com/search?q=' + goods
infolist = []
for i in range(depth):
try:
url = start_url + '&s=' + str(44+i)
html = gethtmltext(url)
parsepage(infolist, html)
except:
continue
printgoodslist(infolist)
main()
实例:股票数据定向爬虫
def gethtmltext(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def getstocklist(lst, stockurl):
html = gethtmltext(stockurl)
soup = BeautifulSoup(html, 'html.parser')
a = soup.find_all('a')
for i in a:
try:
href = i.attrs['href']
lst.append(re.findall(r"[s][hz]\d{6}", href))
except:
continue
def getstockinfo(lst, stockurl, fpath):
for stock in lst:
url = stockurl + stock + '.html'
html = gethtmltext(url)
try:
if html == "":
continue
infodict = []
soup = BeautifulSoup(html, 'html.parser')
stockinfo = soup.find('div', attrs={'class':'stock-bets'})
name = stockinfo.find_all(attrs={'class':'bets-name'})[0]
infodict.update({'股票名称':name.text.split()[0]})
keylist = stockinfo.find_all('dt')
valuelist = stocklist.find_all('dd')
for i in range(len(keylist)):
key = keylist[i].text
val = valuelist[i].text
infodict[key] = val
with open(fpath, 'a', encoding='utf-8') as f:
f.write(str(infodict) + '\n')
def main():
stock_list_url = 'http://quote.eastmoney.com/stocklist.html'
stock_info_url = 'https://gupiao.baidu.com/stock'
output_file = './baiduinfostock.txt'
slist = []
getstocklist(slist, stock_list_url)
getstockinfo(slist, stock_info_url, output_file)
main()