一 . re
1. import re
findall() 查找所有结果
finditer() 查找到的结果返回迭代器
search() 查找. 如果查找到第一个结果,就停止. 如果查找不到结果,返回None
match() 从头开始找,找到第一个就停止
import re # findall()
lst = re.findall('a', 'adfssafdseaa')
print(lst) # finditer()
it = re.finditer('\d+', '这个月28号又发了10000元') # 28 10000
print(it) # <callable_iterator object at 0x000001B488083940> 迭代器
for el in it: # 从迭代器中获取到的el是分组的信息
print(el.group()) # 获取具体信息 # search()
ret = re.search('z', 'adfasfgfewa') # 如果查找不到返回None,则无法调用group,会报错
print(ret.group()) # match()
ret = re.match('a', 'dasffgsafads') # 开头不是a,返回None, ret=None,无法调用group,会报错
print(ret.group())
示例
2. 操作
1. split 切割.按照正则切割
2. sub 替换 subn 替换并显示替换次数
import re
lst = re.split(r'a', 'afssgsdaafgew') # 切a
print(lst) lst1 = re.split(r'[ab]', 'abadffdsabgsagewr') # 切a或b
print(lst1) line = 'abc aa;bb,cc | dd(xx).xxx 12.12\' xxxx' # 按空格切
print(re.split(r' ', line))
print(re.split(r'[ ]', line))
# 按空白切
print(re.split(r'\s', line))
print(re.split(r'[\s]', line))
# 多字符匹配
print(re.split(r'[;,]', line))
# 使用括号捕获分组的时候,默认保留分割符
print(re.split(r'([;])', line))
# 去掉;
print(re.split(r'(?:;)', line))
print(re.split(r';', line))
split示例
import re
# sub 替换
ret = re.sub('', '__sb__', 'alex250taibai250wusir250dd')
print(ret)
# 显示替换了多少次
ret1 = re.subn('', '__sb__', 'alex250taibai250wusir250dd')
print(ret1)
sub和subn示例
爬虫重点: 用compile编译正则表达式
# 爬虫重点
# eval, exec, compile 内置函数回顾
import re
# c = compile('code', 'filename', 'mode') # 代码, 文件名, 模式(eval执行并返回结果, exec执行,不返回结果, single当存放的代码有交互时使用)
li = re.findall(r'\d+', '小明昨天赚了5000块, 小红赚了1000块')
print(li) obj = re.compile(r'\d+') # 编译正则表达式, 当正则表达式过于复杂很长的时候,可以直接使用,不需要复制到代码中
lst = obj.findall('小明昨天赚了5000块, 小红赚了1000块')
print(lst)
(?P<名字> 正则) 把正则匹配到的内容分组成"名字"组
import re
obj = re.compile(r'(?P<id>\d+)(?P<name>e+)') # 从正则表达式匹配的内容每个组起名
字
ret = obj.search('abc123eeee') # 搜索
print(ret.group()) # 结果: 123eeee
print(ret.group("id")) # 结果: 123 # 获取id组的内容
print(ret.group("name")) # 结果: eeee # 获取name组的内容
正则:在python中()表示分组 (?:)去掉python的分组 ()在split中表示保留刀
import re
ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组⾥内容返回,如果想要匹
配结果,取消权限即可
ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
print(ret) # ['www.oldboy.com']
import re
ret=re.split("\d+","eva3egon4yuan")
print(ret) #结果 : ['eva', 'egon', 'yuan']
ret=re.split("(\d+)","eva3egon4yuan")
print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']
#在匹配部分加上()之后所切出的结果是不同的,
#没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,
#这个在某些需要保留匹配部分的使⽤过程是⾮常重要的。
利用优先级问题解决问题,爬取信息
re.S 能忽略掉.不能匹配\n的问题 取值关键
用charset查看编码模式 charset=gb2312 # 编码模式 gbk
import re
from urllib.request import urlopen
import ssl
# ⼲掉数字签名证书
ssl._create_default_https_context = ssl._create_unverified_context
def getPage(url):
response = urlopen(url) # 和网页链接
return response.read().decode('utf-8') # 返回正常的页面源代码, 一大堆HTML
def parsePage(s): # s是页面源代码
ret = re.findall('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?'+
'<span class="title">(?P<title>.*?)</span>'+'.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>'+
'(?P<comment_num>.*?)评价</span>', s, re.S) # re.S 能忽略掉.不能匹配\n的问题
return ret
def main(num):
url = 'https://movie.douban.com/top250?start=%s&filter=' % num
response_html = getPage(url) # 页面源代码
ret = parsePage(response_html)
print(ret)
count = 0
for i in range(10): # 10⻚
main(count)
count += 25 main(1)
import re
from urllib.request import urlopen def getContent(url):
return urlopen(url).read().decode("gbk")
# # 爬取 http://www.dytt8.net/ 上的内容
url = "http://www.dytt8.net"
content = getContent(url)
# 准备正则
obj = re.compile(r"\[<a .*?>最新电影下载</a>\]<a href='(?P<second_url>.*?)'>.*?</a>", re.S)
second_obj = re.compile(r'<div id="Zoom">.*?译 名(?P<yiming>.*?)<br />◎片 名(?P<pianming>.*?)<br />.*?◎导 演(?P<daoyan>.*?)<br />◎主 演(?P<zhuyan>.*?)<br /><br />◎简 介.*?<td .*?><a href="(?P<download>.*?)">', re.S) it = obj.finditer(content)
for el in it:
second_url = el.group("second_url")
second_content = getContent(url+second_url)
second_it = second_obj.finditer(second_content) # 拿到第二层通过正则匹配到的内容.
print("************************************************************************")
for second_info in second_it:
print(re.sub("[\u3000]", "", second_info.group("yiming")))
print(re.sub("[\u3000]", "", second_info.group("pianming")))
print(re.sub("[\u3000]", "", second_info.group("daoyan")))
print(re.split("<br />", re.sub("[\u3000]", "", second_info.group("zhuyan"))))
print(re.sub("[\u3000]", "", second_info.group("download"))) '''
content = urlopen("http://www.dytt8.net").read().decode('gbk')
因为用到多次,所以写成函数以便调用
def getContent(url):
return urlopen(url).read().decode('gbk') '''
爬取电影信息
import re
from urllib.request import urlopen def getContent(url): # 提取出功能方便多次调用
return urlopen(url).read().decode('gbk') # 获取源码 url = "http://www.dytt8.net"
content = getContent(url) # 获取源码
# print(content) # 可查看源码 # 准备正则
regular1 = re.compile(r"最新电影下载</a>]<a href='(?P<info_url>.*?)'>.*?</a><br/>", re.S)
regular2 = re.compile(r'◎译 名 (?P<trans_name>.*?)<br />◎片 名 (?P<name>.*?)<br />.*?◎豆瓣评分 (?P<grade>.*?)/10'+
' from (?P<grade_num>.*?) users <br />.*?◎导 演 (?P<director>.*?) <br />◎主 演 (?P<actors>.*?) <br /><br />◎简 介'+
'.*?bgcolor="#fdfddf"><a href="(?P<download_url>.*?)">', re.S) name_url_iter = re.finditer(regular1, content)
for el in name_url_iter:
info_url = el.group('info_url')
content2 = getContent(url + info_url)
info_iter = regular2.finditer(content2)
for el2 in info_iter:
print('*****************************************************************************')
print('译名:', el2.group('trans_name'))
print('片名:', el2.group('name'))
print('豆瓣评分:', el2.group('grade'))
print('评分数量:', el2.group('grade_num'))
print('导演:', el2.group('director'))
print('主演:', re.split(r' <br /> ', el2.group('actors').replace('·', '·')))
print('下载地址:', el2.group('download_url'))
我的版本
import re, json
from urllib.request import urlopen def getContent(url): # 提取出功能方便多次调用
# print(url)
return urlopen(url).read().decode('gbk') # 获取源码 f = open('更多电影.txt', mode='a', encoding='utf-8')
# 准备正则
regular1 = re.compile(r'<b>.*?<a href="(?P<info_url>.*?)".*?', re.S)
regular2 = re.compile(r'◎译 名 (?P<trans_name>.*?) <.*?名 (?P<name>.*?) <.*?代 (?P<date>.*?) <.*?评分 ' +
'(?P<grade>.*?)/.*?bgcolor="#fdfddf"><a href="(?P<download_url>.*?)">', re.S) for i in range(4):
url = "http://www.dytt8.net/html/gndy/dyzz/list_23_%s.html" % (i+1)
content = getContent(url) # 获取源码
# print(content) # 可查看源码 name_url_iter = re.finditer(regular1, content)
for el in name_url_iter:
info_url = el.group('info_url')
content2 = getContent('http://www.dytt8.net' + info_url)
info_iter = regular2.finditer(content2)
for el2 in info_iter:
# print('*****************************************************************************')
print('译名:', el2.group('trans_name'))
print('片名:', el2.group('name'))
print('豆瓣评分:', el2.group('grade'))
print('上映日期:', el2.group('date'))
print('下载地址:', el2.group('download_url'))
dic = {}
dic['译名'] = el2.group('trans_name')
dic['片名'] = el2.group('name')
dic['豆瓣评分'] = el2.group('grade')
dic['上映日期'] = el2.group('date')
dic['下载地址:'] = el2.group('download_url')
s = json.dumps(dic, ensure_ascii=False) + '\n'
f.write(s) f.close()
爬更多页,写入文件
二. 模块 模块就是⼀个包含了python定义和声明的⽂件, ⽂件名就是模块的名字加上.py后缀. 换句话说我们⽬前写的所有的py⽂件都可以
看成是⼀个模块,但是我们import加载的模块⼀共分成四个通⽤类别:
1. 使⽤pyhton编写的py⽂件
2. 已被编译为共享库或者DLL或C或者C++的扩展
3. 包好⼀组模块的包.
4. 使⽤c编写并连接到python解释器的内置模块 import 模块名
1. 检查是否已经导入过 , 顺序, 内存-> 内置 -> sys.path
2. 如果没有导入过这个模块. 先创建一个名称空间
3. 然后把导入的模块执行一遍. 把执行的结果放在刚才的空间中
4. 当没有as的时候是使用模块的名字来引用这个名称空间. 当有as的时候. 用as的名字命名空间
# 创建文件yitian.py
print("啊` 啊 啊啊 啊啊啊啊啊 啊!!!!") main_person_man = "张无忌"
main_person_woman = "赵敏" bad_person_one = "成昆"
bad_person_two = "周芷若" def fight_on_light_top(): print(main_person_man, "粉碎了",bad_person_one ,"的阴谋") def fight_in_shaolin():
print(main_person_man, "粉碎了", bad_person_two, "的阴谋")
创建文件yitian.py,文件名yitian即模块名
import yitian as yt print(yt.main_person_man)
yt.fight_in_shaolin() # 调⽤模块中的函数
yt.fight_on_light_top() print(globals()) # 可以查看 当前空间中引入的内容 # # 模块的加载顺序: 从内存里找. -> 内置 -> sys.path
# import sys
# print(sys.modules.keys()) # 查看到已经引入的模块信息
# print(sys.path)
导入模块,模块名更改
在Python中模块是不能够重复导入的. 当重复导入模块时. 系统会根据sys.modules来判断该模块是否已经导入了. 如果已经导入. 则不会重复导入
import sys
print(sys.modules.keys()) # 查看导⼊的模块.
import yitian # 导⼊模块. 此时会默认执⾏该模块中的代码
import yitian # 该模块已经导⼊过了. 不会重复执⾏代码
import yitian
import yitian
import yitian
import yitian
所有被导入的模块都会放在sys.modules字典里
使用模块中的内容. 模块名字.方法/变量/类
from time import * # 引入time模块的所有对象. *代表所有对象: 变量,类,函数,引入后调用无需 模块名. 直接使用即可time() 如果直接import time,则调用时需要time.time()
print(time()) print(sys.path) # 查看路径
print(sys.modules) # 查看导入的模块,是一个字典
print(sys.modules.keys())
由于模块在导入的时候会创建其⾃⼰的名称空间. 所以. 我们在使⽤模块中的变量的时候⼀般是不会产⽣冲突的.
import yitian
main_person_man = "胡⼀菲"
def fight_in_shaolin():
print(main_person_man, "⼤战曾⼩贤")
print(yitian.main_person_man) # 张⽆忌
print(main_person_man) # 胡⼀菲
yitian.fight_in_shaolin() # 倚天屠⻰记中的
fight_in_shaolin() # ⾃⼰的
__name__:
如果当前模块是程序的入口. __name__的值:__main___
如果模块是被其他模块引入的. __name__是模块名
⾦庸:
import yitian
yitian.main_person_man = "灭绝师太"
⾦庸⼆号:
import yitian
import ⾦庸
print(yitian.main_person_man) # 灭绝师太. ⾦庸:
print(__name__)
# 此时如果运⾏该⽂件. 则__name__是__main__
⾦庸⼆号:
import ⾦庸
#此时打印的结果是"⾦庸" (引入的模块名,在哪个引入模块中调用__name__,则显示哪个模块名)
我们可以利⽤这个特性来控制模块内哪些代码是在被加载的时候就运⾏的. 哪些是在模
块被别⼈导入的时候就要执⾏的. 也可以屏蔽掉⼀些不希望别⼈导入就运⾏的代码. 尤其是测
试代码.
if __name__ == '__main__':
yitian.main_person_man = "灭绝师太" # 此时, 只有从该模块作为⼊⼝运⾏的时候才
会把main_person_man设置成灭绝师太
print("哇哈哈哈哈哈") # 只有运⾏该模块才会打印. import的时候是不会执⾏这⾥的代
码的
一次可以引入多个模块
import time, random, json, yitian
from xxx import xxx
from 模块 import 模块中的内容
from 模块 import * 不推荐 导入的内容可以直接使用. 不需要模块.xxx. 不要和当前模块中的变量冲突
from yitian import main_person_man #也可以一行引入多个,也支持as改名字 main_person_man = "灭绝" # 引入的名字和自己的变量是冲突的
print(main_person_man) # 先找 内存=>内置=>模块 此处打印自己的变量
所以. 不要重名. 切记. 不要重名! 不仅仅是变量名不要重复.我们⾃⼰创建的py⽂件的名字不要和系统内置的模块重名. 否则. 引入的模块都是python内置的模块. 切记, 切记.
如果确实需要用同样的名字,可以 my_模块名.py e.g. my_sys.py