Python模块之re模块、第三方包、openpyxl模块
re模块
在python中如果想要使用正则表达式,re模块是选择之一
re 模块使 Python 语言拥有全部的正则表达式功能。
findall
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。
ps:findall通过正则表达式筛选出文本中所有符合条件的数据,match 和 search 是匹配一次 findall 匹配所有
# 语法格式
re.findall(pattern, string, flags=0)
或
pattern.findall(string[, pos[, endpos]])
参数:
- pattern 匹配模式(正则表达式)。
- flags 标志位,用于控制正则表达式的匹配方式
- string 待匹配的字符串。
- pos 可选参数,指定字符串的起始位置,默认为 0。
- endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
例
>>> import re
# 查找字符串中所有a
>>> res = re.findall('a', 'kwan oscar aaa') # 返回所有满足匹配条件的结果,放在列表里
>>> res
['a', 'a', 'a', 'a', 'a']
# 多个匹配模式,返回元组列表:
>>> res = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
>>> res
[('width', '20'), ('height', '10')]
re.finditer
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回, 节省内存。
# 语法格式
re.finditer(pattern, string, flags=0)
例
>>> import re
>>> res = re.finditer('a', 'kwan oscar aaa')
>>> res
<callable_iterator object at 0x0000025941F3FA30>
re.match 和 re.search
- re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
- re.search 扫描整个字符串并返回第一个成功的匹配。
# 语法格式
re.match(pattern, string, flags=0)
re.search(pattern, string, flags=0)
匹配成功re.match、re.search方法都会返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
| 匹配对象方法 | 描述 |
|---|---|
| group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
| groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
>>> import re
# 不在起始位置匹配
>>> res = re.match('a', 'kwan oscar aaa') # re.match
>>> print(res)
None
>>> res = re.search('a', 'kwan oscar aaa') # re.search
>>> print(res)
<re.Match object; span=(2, 3), match='a'>
# 在起始位置匹配
>>> res = re.match('a', 'aaa kwan oscar') # re.match
>>> print(res)
<re.Match object; span=(0, 1), match='a'>
>>> res = re.search('a', 'aaa kwan oscar') # re.search
>>> print(res)
<re.Match object; span=(0, 1), match='a'>
>>> print(res.group()) # group(),两者都是返回 a
a
# group()
>>> import re
>>>
>>> line = "Cats are smarter than dogs"
>>> # .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
>>> # (.*?) 表示"非贪婪"模式,只保存第一个匹配到的子串
>>> matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I) # match/search group()结果一样
>>>
>>> if matchObj:
... print ("matchObj.group() : ", matchObj.group())
... print ("matchObj.group(1) : ", matchObj.group(1))
... print ("matchObj.group(2) : ", matchObj.group(2))
... else:
... print ("No match!!")
...
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
re.match与re.search的区别
re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。
>>> import re
>>>
>>> line = "Cats are smarter than dogs"
>>>
>>> matchObj = re.match( r'dogs', line, re.M|re.I) # re.match
>>> if matchObj:
... print ("match --> matchObj.group() : ", matchObj.group())
... else:
... print ("No match!!")
...
No match!!
>>>
>>> matchObj = re.search( r'dogs', line, re.M|re.I) # re.search
>>> if matchObj:
... print ("search --> matchObj.group() : ", matchObj.group())
... else:
... print ("No match!!")
...
search --> matchObj.group() : dogs
compile 函数
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。可以反复使用,减少代码冗余。
# 语法格式
re.compile(pattern[, flags])
参数:
pattern : 一个字符串形式的正则表达式
flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
re.I 忽略大小写
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
- re.M 多行模式
- re.S 即为' . '并且包括换行符在内的任意字符(' . '不包括换行符)
- re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
- re.X 为了增加可读性,忽略空格和' # '后面的注释
>>> import re
>>> obj = re.compile('a')
>>> print(re.findall(obj,'sdsd14dasd2167dafg'))
['a', 'a']
>>> print(re.findall(obj,'fssd45adscxaazxczx'))
['a', 'a', 'a']
>>> print(re.findall(obj,'dadadafdsadaasfffd'))
['a', 'a', 'a', 'a', 'a', 'a']
>>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字
>>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配
>>> print( m )
None
>>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
>>> print( m )
None
>>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
>>> print( m ) # 返回一个 Match 对象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0) # 可省略 0
'12'
>>> m.start(0) # 可省略 0
3
>>> m.end(0) # 可省略 0
5
>>> m.span(0) # 可省略 0
(3, 5)
当匹配成功时返回一个 Match 对象,其中:
group([group1, …])方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用group()或group(0);start([group])方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;end([group])方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;span([group])方法返回(start(group), end(group))。
re模块补充说明
分组
>>> res = re.findall('adb', 'asadbaadbfabddsadb')
>>> print(res)
['adb', 'adb', 'adb']
>>>
>>> res = re.findall('a(d)b', 'asadbaadbfabddsadb')
>>> print(res) # 这是因为findall会 优先 把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
['d', 'd', 'd']
>>>
>>> res = re.findall('a(?:d)b', 'asadbaadbfabddsadb') # 取消分组优先展示 (?:)
>>> print(res)
['adb', 'adb', 'adb']
别名
>>> import re
>>> ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>", "<h1>hello</h1>")
# 还可以在分组中利用?<name>的形式给分组起名字
# 获取的匹配结果可以直接用group('名字')拿到对应的值
>>> print(ret.group('tag_name'))
h1
>>> print(ret.group())
<h1>hello</h1>
>>> ret = re.search(r"<(\w+)>\w+</\1>", "<h1>hello</h1>")
>>> # 如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致
>>> # 获取的匹配结果可以直接用group(序号)拿到对应的值
>>> print(ret.group(1))
h1
>>> print(ret.group())
<h1>hello</h1>
第三方模块下载
- 第三方模块必须先下载才可以导入使用
- python下载第三方模块需要借助于pip工具
- 下载命令
pip3 install 模块名
pip安装
通过以下命令来判断是否已安装:
pip --version # Python2.x 版本命令
pip3 --version # Python3.x 版本命令
如果你还未安装,则可以使用以下方法来安装:
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py # 下载安装脚本
$ sudo python get-pip.py # 运行安装脚本
注意:用哪个版本的 Python 运行安装脚本,pip 就被关联到哪个版本,如果是 Python3 则执行以下命令:
$ sudo python3 get-pip.py # 运行安装脚本。一般情况 pip 对应的是 Python 2.7,pip3 对应的是 Python 3.x。
注意事项
如果 Python2 和 Python3 同时有 pip,则使用方法如下:
Python2:
python2 -m pip install XXX
Python3:
python3 -m pip install XXX
下载速度慢的问题
pip工具默认是从国外的仓库地址下载模块,速度很慢时可以使用国内镜像下载(源地址)
清华大学 :https://pypi.tuna.tsinghua.edu.cn/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科学技术大学 :http://pypi.mirrors.ustc.edu.cn/simple/
华中科技大学:http://pypi.hustunique.com/
豆瓣源:http://pypi.douban.com/simple/
临时使用:
pip install -i 包名 https://pypi.tuna.tsinghua.edu.cn/simple
例如,安装 Django:
pip install -i Django https://pypi.tuna.tsinghua.edu.cn/simple
网络爬虫
-
什么是互联网
将全世界的计算机连接到一起组成的网络
-
互联网发明的目的是什么
将接入互联网的计算机上面的数据彼此共享
-
上网的本质是什么
基于互联网访问别人计算机上面的资源(有些计算机存在的意义就是让别人访问,这种类型的计算机我们也称之为服务器)
-
网络爬虫的本质
模拟计算机浏览器朝目标网址发送请求回去数据并筛选
只要是浏览器可以访问到的数据网络爬虫理论上都可以
爬取公司信息
requests 方法
requests 方法如下表:
| 方法 | 描述 |
|---|---|
| delete(url, args) | 发送 DELETE 请求到指定 url |
| get(url, params, args) | 发送 GET 请求到指定 url |
| head(url, args) | 发送 HEAD 请求到指定 url |
| patch(url, data, args) | 发送 PATCH 请求到指定 url |
| post(url, data, json, args) | 发送 POST 请求到指定 url |
| put(url, data, args) | 发送 PUT 请求到指定 url |
| request(method, url, args) | 向指定的 url 发送指定的请求方法 |
每次调用 requests 请求之后,会返回一个 response 对象,该对象包含了具体的响应信息。
import requests
# 朝目标地址发送网络请求获取响应数据(相当于在浏览器地址栏中输入网址并回车)
res = requests.get('http://www.redbull.com.cn/about/branch')
print(res.content) # 获取bytes类型的数据
print(res.text) # 获取解码之后的数据
# 为了避免每次执行程序都要发送网络请求 也可以提前保存页面数据到文件
with open(r'hn.html','wb') as f:
f.write(res.content)
import re
# 读取页面数据
with open(r'hn.html', 'r', encoding='utf8') as f:
data = f.read()
# 研究目标数据的特征 编写正则筛选
# 1.获取所有的分公司名称
company_name_list = re.findall('<h2>(.*?)</h2>', data)
# print(res)
# 2.获取所有的分公司地址
company_addr_list = re.findall("<p class='mapIco'>(.*?)</p>", data)
# print(company_addr_list)
# 3.获取所有的分公司邮箱
company_email_list = re.findall("<p class='mailIco'>(.*?)</p>", data)
# print(company_email_list)
# 4.获取所有的分公司电话
company_phone_list = re.findall("<p class='telIco'>(.*?)</p>", data)
# print(company_phone_list)
# 5.将上述四个列表中的数据按照位置整合
res = zip(company_name_list, company_addr_list, company_email_list, company_phone_list)
# 6.处理数据(展示 保存 excel)
for i in res: # ('红牛杭州分公司', '杭州市上城区庆春路29号远洋大厦11楼A座', '310009', '0571-87045279/7792')
print("""
公司名称:%s
公司地址:%s
公司邮箱:%s
公司电话:%s
""" % i)
openpyxl模块
-
openpyxl 是个读写 Excel 2010 xlsx/xlsm/xltx/xltm 的 Python 库,简单易用,功能广泛,单元格格式/图片/表格/公式/筛选/批注/文件保护等等功能应有尽有,图表功能是其一大亮点
-
OpenPyXl 几乎可以实现所有的 Excel 功能,主要用于操作excel表格,也是pandas底层操作表格的模块
excel版本问题
03版本之前 excel文件的后缀名 .xls
03版本之后 excel文件的后缀名 .xlsx
如果是苹果电脑excel文件的后缀 .csv
安装
用 pip 安装
pip3 install openpyxl
openpyxl实操
# 1.创建excel文件
from openpyxl import Workbook # 导入模块
wb = Workbook() # 创建excel文件
wb1 = wb.create_sheet('成绩表')
wb2 = wb.create_sheet('财务表')
wb3 = wb.create_sheet('校花表', 0)
wb1.title = '开黑表' # 支持二次修改
wb1.sheet_properties.tabColor = "1072BA" # 修改工作簿颜色
wb.save(r'kk.xlsx') # 保存文件
# 2.写入数据
# 第一种写入方式
wb1['A1'] = '???'
wb1['B2'] = 'DDD'
# 第二种写入方式
wb1.cell(row=3, column=3, value='你瞅啥')
# 第三种写入方式(批量写入)
wb1.append(['username', 'password', 'age', 'gender', 'hobby'])
wb1.append(['kwan1', 123, 18, 'female', 'read'])
wb1.append(['kwan2', 123, 18, 'female', 'read'])
wb1.append(['kwan3', 123, 18, 'female', 'read'])
wb1.append(['kwan4', 123, 18, 'female', 'read'])
wb1.append(['kwan4', 123, 18, 'female', None])
wb1.append([None, 123, 18, 'female', ''])
wb1['F11'] = '=sum(B5:B10)' # 计算单元格B5到B10的和
wb.save(r'111.xlsx') # 保存文件

作业
import requests
import re
from openpyxl import Workbook
# 朝目标地址发送网络请求获取响应数据(相当于在浏览器地址栏中输入网址并回车)
res = requests.get('http://www.redbull.com.cn/about/branch')
# 为了避免每次执行程序都要发送网络请求 也可以提前保存页面数据到文件
with open(r'hn.html', 'wb') as f:
f.write(res.content)
# 读取页面数据
with open(r'hn.html', 'r', encoding='utf8') as f:
data = f.read()
# 研究目标数据的特征 编写正则筛选
# 获取所有的分公司名称
company_name_list = re.findall('<h2>(.*?)</h2>', data)
# 获取所有的分公司地址
company_addr_list = re.findall("<p class='mapIco'>(.*?)</p>", data)
# 获取所有的分公司邮箱
company_email_list = re.findall("<p class='mailIco'>(.*?)</p>", data)
# 获取所有的分公司电话
company_phone_list = re.findall("<p class='telIco'>(.*?)</p>", data)
# 将上述四个列表中的数据按照位置整合
res = zip(company_name_list, company_addr_list, company_email_list, company_phone_list)
# 创建excel文件
wb = Workbook()
# 创建一个sheet
ws = wb.create_sheet("hn_sheet")
# 填入数据
ws.append(['分公司名称', '分公司地址', '分公司邮箱', '分公司电话'])
for i in res:
ws.append(i)
# 保存文件
wb.save(r'hn.xlsx')


浙公网安备 33010602011771号