python爬虫-----网络数据分析
一、正则表达式
1.为什么要学正则表达式
爬虫一共四个主要步骤:
- 明确目标 (要知道你准备在哪个范围或者网站去搜索)
- 爬 (将所有的网站的内容全部爬下来)
- 取 (去掉对我们没用处的数据)
- 处理数据(按照我们想要的方式存储和使用)
2.什么是正则表达式
正则表达式,又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。
3.re 模块一般使用步骤
- 使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象
注意: re对特殊字符进行转义,如果使用原始字符串,只需加一个 r 前缀 - 通过 Pattern 对象对文本进行匹配查找,获得匹配结果,一个 Match 对象。
- 使用 Match 对象提供的属性和方法获得信息,根据需要进行其他的操作
Pattern 对象
正则表达式编译成 Pattern 对象, 可以利用 pattern 的一系列方法对文本进行匹配查找了。
Pattern 对象的一些常用方法主要有:
match 方法:从起始位置开始查找,一次匹配
search 方法:从任何位置开始查找,一次匹配
findall 方法:全部匹配,返回列表
finditer 方法:全部匹配,返回迭代器
split 方法:分割字符串,返回列表
sub 方法:替换
正则表达式实现步骤
import re
text = """
2020-10-10
2020-11-11
2030/12/12
"""
# 1. 使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象
# 注意: re对特殊字符进行转义,如果使用原始字符串,只需加一个 r 前缀
pattern = re.compile(r'\d{4}-\d{1,2}-\d{1,2}') # 2020-4-11, 无分组的规则
pattern = re.compile(r'(\d{4})-(\d{1,2})-(\d{1,2})') # 2020-4-11, 有分组的规则
pattern = re.compile(r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})') # 2020-4-11, 有命名分组的规则
# 2. 通过 Pattern 对象对文本进行匹配查找,获得匹配结果,一个 Match 对象。
# search从给定的字符串中寻找一个符合规则的字符串, 只返回一个
result = re.search(pattern, text)
print(result)
# 3. 使用 Match 对象提供的属性和方法获得信息,根据需要进行其他的操作
print("匹配到的信息:", result.group()) # 返回的是匹配到的文本信息
print("匹配到的信息:", result.groups()) # 返回的是位置分组, ('2020', '10', '10')
print("匹配到的信息:", result.groupdict()) # 返回的是关键字分组.{'year': '2020', 'month': '10', 'day': '10'}
#运行结果:
<re.Match object; span=(1, 11), match='2020-10-10'>
匹配到的信息: 2020-10-10
匹配到的信息: ('2020', '10', '10')
匹配到的信息: {
'year': '2020', 'month': '10', 'day': '10'}
4.正则split和sub
repl 可以是字符串也可以是一个函数:
1). 如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还 可以使用 id 的形式来引用分组,但不能使用编号 0;
2). 如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符 串中不能再引用分组)。
count 用于指定最多替换次数,不指定时全部替换。
正则匹配中文
在某些情况下,我们想匹配文本中的汉字,有一点需要注意的是,中文的 unicode 编码范围 主要在 [u4e00- u9fa5],这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是 够用的。
import re
# ****************************split***************************
# text = '1+2*4+8-9/10'
# # 字符串方法: '172.25.254.250'.split('.') => ['172', '25', '254', '250']
# pattern = re.compile(r'\+|-|\*|/')
# # 将字符串根据+或者-或者*或者/进行切割.
# result = re.split(pattern, text)
# print(result) #['1', '2', '4', '8', '9', '10']
# #***********************sub**************************************
def repl_string(matchObj):
# matchObj方法: group, groups, groupdict
items = matchObj.groups()
# print("匹配到的分组内容: ", items) # ('2019', '10', '10')
return "-".join(items)
# 2019/10/10 ====> 2019-10-10
text = "2019/10/10 2020/12/12 2019-12-10 2020-11-10"
pattern = re.compile(r'(\d{4})/(\d{1,2})/(\d{1,2})') # 注意: 正则规则里面不要随意空格
# 将所有符合条件的信息替换成'2019-10-10'
# result = re.sub(pattern, '2019-10-10', text)
# 将所有符合条件的信息替换成'year-month-day'
result = re.sub(pattern, repl_string, text)
print(result) #2019-10-10 2020-12-12 2019-12-10 2020-11-10
5.常用的正则常量
正则表达式在线测试
https://c.runoob.com/front-end/854
"""
常用的正则常量:
"ASCII": 'A'
"IGNORECASE": 'I'
"MULTILINE":'M'
"DOTALL":'S'
"""
import re
# ******************************** 1. re.ASCII *****************************
text = "正则表达式re模块是python中的内置modelue."
# 匹配所有的\w+(字母数字下划线, 默认也匹配中文), 不想匹配中文时,指定flags=re.A
result = re.findall(r'\w+', string=text, flags=re.A)
print(result) #['re', 'python', 'modelue']
# ******************************** 2. re.IGNORECASE *****************************
text = 'hello world heLLo westos Hello python'
# 匹配所有he\w+o, 忽略大小写, re.I
result = re.findall(r'he\w+o', text, re.I)
print(result) # ['hello', 'heLLo', 'Hello']
# # ******************************** 3. re.S *****************************
text = 'hello \n world'
result = re.findall(r'^he.*?ld$', text, re.S)
print(result) #['hello \n world']
# # ************************匹配中文**********************
pattern = r'[\u4e00-\u9fa5]'
text = "正则表达式re模块是python中的内置modelue."
result = re.findall(pattern, text)
print(result) #['正', '则', '表', '达', '式', '模', '块', '是', '中', '的', '内', '置']
项目案例:基于requests和正则 的猫眼电影TOP100定向爬虫
import codecs
import json
import re
import time
import requests
from colorama import Fore
from fake_useragent import UserAgent
from requests import HTTPError
def download_page(url, parmas=None):
"""
根据url地址下载html页面
:param url:
:param parmas:
:return: str
"""
try:
ua = UserAgent()
headers = {
'User-Agent': ua.random,
'Host': 'maoyan.com',
'Cookie': '__mta=244103482.1586583849431.1586591578863.1586591596622.7; uuid_n_v=v1; uuid=70A8E5507BB711EA904101D407E7401D56771E011B5248CCB28F41E623827FA2; _csrf=911258e83ffafda305001ded783784bef80e9113d1d47c8f8b4940dc934b9acd; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1586583838; mojo-uuid=1bf14bca5d2a510f6e85c2857cc8d257; _lxsdk_cuid=17167c43f33c8-07022459d688ce-4313f6a-144000-17167c43f33c8; _lxsdk=70A8E5507BB711EA904101D407E7401D56771E011B5248CCB28F41E623827FA2; mojo-session-id={"id":"83a8b6a56c45ba34bd30bd7e6d5c46b9","time":1586591446957}; __mta=244103482.1586583849431.1586583890672.1586591526586.6; mojo-trace-id=6; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1586591597; _lxsdk_s=171683837b1-2a5-86f-f4e%7C%7C10'
}
# 请求https协议的时候, 回遇到报错: SSLError
# verify=Flase不验证证书
response = requests.get(url, params=parmas, headers=headers)
except HTTPError as e:
print(Fore.RED + '[-] 爬取网站%s失败: %s' % (url, str(e)))
return None
else:
# content返回的是bytes类型, text返回字符串类型
return response.text
def parse_html(html):