正则表达式
通过一个模式pattern去匹配文本的内容,提炼出自己想要的数据;
需要应用re这个库。
1.match()方法
从字符串的开头开始匹配,匹配到了就返回第一个匹配到的内容,如果一开始就不匹配就返回None。
import re
content="Hello 123 4567 World_This is a Regex Demo"
result=re.match('^Hello\\s\\d\\d\\d\\s\\d{4}\\s\\w{10}',content)
print(result.group()) #返回Hello 123 4567 World_This
print(result.span()) #span()方法会返回匹配的索引,返回匹配的位置(0,25)
2.group()方法会返回匹配的内容
如果想要匹配某个目标,可以使用括号着重标记,括号的作用是标记一个子表达式的开始和结束位置,被标记的子表达式会依次对应一个分组,调用group()方法传入索引可以获得提取的结果
比如
content="Hello 123 4567 World_This is a Regex Demo"
想要用表达式去匹配以上这个内容
pattern='^Hello\\s\\d{3}\\s\\d{4}\\s\\w{10}\\s\\w{2}\\s\\w\\s\\w{5}\\s\\w{4}'
import re
content="Hello 123 4567 World_This is a Regex Demo"
result=re.match('^Hello\\s\\d{3}\\s\\d{4}\\s\\w{10}\\s\\w{2}\\s\\w\\s\\w{5}\\s\\w{4}',content)
print(result.group()) #返回完整的content
如果只需要返回数字
pattern='^Hello\\s(\\d{3})\\s\\(d{4})\\s\\w{10}\\s\\w{2}\\s\\w\\s\\w{5}\\s\\w{4}'
import re
content="Hello 123 4567 World_This is a Regex Demo"
result=re.match('^Hello\\s(\\d{3})\\s(\\d{4})\\s\\w{10}\\s\\w{2}\\s\\w\\s\\w{5}\\s\\w{4}',content)
print(result.group(1)) #返回123
print(result.group(2)) #返回4567
3.search()方法
不局限于从字符串的开头开始匹配,匹配到了就返回第一个匹配到的内容。
1.如果运用match方法
import re
content="Extra Hello 123 4567 World_This is a Regex Demo"
result=re.match('Hello\\s(\\d+)\\s',content)
print(result) #返回None
2.如果运用search方法
import re
content="Extra Hello 123 4567 World_This is a Regex Demo"
result=re.search('Hello\\s(\\d+)\\s',content)
print(result) #返回<re.Match object; span=(6, 16), match='Hello 123 '>
4.贪婪匹配和非贪婪匹配
如果想获取content中的数字1234567
1.贪婪匹配.*
import re
content="Hello 1234567 World_This is a Regex Demo"
result=re.match('^He.*(\\d+).*Demo$',content)
print(result.group(1)) #输出7
分析原因:
贪婪匹配会尽可能匹配更多,所以这里尽可能多的匹配到数字
2.非贪婪匹配.*?
import re
content="Hello 1234567 World_This is a Regex Demo"
result=re.match('^He.*?(\\d+).*Demo$',content)
print(result.group(1)) #输出1234567
如果匹配的结果在字符串结尾,因为他尽可能少的匹配字符,所以.*?就匹配不到任何内容了
比如
content='http://weibo.com/comment/test'
result1=re.match('http.*?comment/(.*?)',content)
result2=re.match('http.*?comment/(.*)',content)
print(result1.group(1)) #返回空
print(result2.group(1)) #返回test
5.findall()方法
匹配字符串中所有符合模式pattern的内容,返回所有匹配项。
如果针对以下html内容
html='''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="intrpduction">
经典老歌列表
</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>'''
针对以上的内容,提取歌手名字和歌名
re.S的作用
使得模式可以匹配到换行
1.不加re.S
result=re.search('<li.*?singer="(.*?)">(.*?)</a>',html)
if result:
print(result.group(1),result.group(2))
#输出beyond 光辉岁月
2.加re.S
result=re.search('<li.*?singer="(.*?)">(.*?)</a>',html,re.S)
if result:
print(result.group(1),result.group(2))
#任贤齐 沧海一声笑
search()只返回了一个内容
3.使用search
results=re.search('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',html,re.S)
print(results)
#输出<re.Match object; span=(121, 208), match='<li data-view="2">一路上有你</li>\n<li data-view="7">\>
4.使用findall()
results=re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',html,re.S)
for result in results:
print(result[0],result[1],result[2])#输出所有内容
6.sub()方法
指定模式pattern,对所有符合pattern的数据作替换,相比replace()方法功能更强大。
举例:将数字替换为空
content='54aK54yI5oiR54ix5L2g'
content=re.sub('\\d+','',content)
print(content) #输出aKyIoiRixLg
7.compile()方法
将模式pattern编译成一个可复用的模式,方便后续直接调用。
举例:去掉时间,保留日期
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)
#输出2016-12-15 2016-12-17 2016-12-22
实例:抓取猫眼电影top100
import json
import re
import requests
import time
def get_one_page(url):
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0'
}
response=requests.get(url,headers=headers)
# print(f"状态码: {response.status_code}")
if response.status_code==200:
return response.text
return None
def parse_one_page(html):
pattern=re.compile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>',re.S)
items=re.findall(pattern,html)
for item in items:
yield {
'index':item[0],
'image':item[1],
'title':item[2].strip(),
'actor':item[3].strip()[3:] if len(item[3])>3 else '',
'time':item[4].strip()[5:] if len(item[4])>5 else '',
'score':item[5].strip()+item[6].strip()
}
def write_to_file(content):
with open('result.txt','a',encoding='utf-8') as f:
print(type(json.dumps(content)))
f.write(json.dumps(content,ensure_ascii=False)+'\n')
def main(offset):
url='http://maoyan.com/board/4'+'?offset='+str(offset)
html=get_one_page(url)
for item in parse_one_page(html):
print(item)
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
main(offset=i*10)
time.sleep(60)