Day25--Python--re,模块(regular expression)

一 . 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())
View Code 示例

 

    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))
View Code split示例
import re
# sub 替换
ret = re.sub('250', '__sb__', 'alex250taibai250wusir250dd')
print(ret)
# 显示替换了多少次
ret1 = re.subn('250', '__sb__', 'alex250taibai250wusir250dd')
print(ret1)
View Code 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)
View Code

    (?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')

'''
View Code爬取电影信息

 

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('&middot;', '·')))
        print('下载地址:', el2.group('download_url'))
View Code 我的版本

 

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()
View Code 爬更多页,写入文件

 

二. 模块

     模块就是⼀个包含了python定义和明的⽂, 名就是模块的名字加上.py. 换句话说我们⽬前写的所有的py都可以
     看成是⼀个模块,但是我们import的模块⼀分成四个通⽤类:
       1. 使⽤pyhton编写的py
       2. 已被编译共享库或者DLLC或者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, "的阴谋")
View Code 创建文件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)
View Code 导入模块,模块名更改

      在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

posted @ 2018-10-11 19:58  SuraSun  阅读(256)  评论(0编辑  收藏  举报