爬虫入门(re)

112 阅读7分钟

数据解析概述

1.re解析

2.bs4解析

3.xpath解析

re模块的使用

re.findall函数

搜索整个字符串,返回一个list

语法如下:re.findall(string)

import re

# findall:匹配字符串中所有的符合正则的内容
lst = re.findall(r"\d+","我的电话号码是:10086")
print(lst)

['10086']

# finditer:匹配字符串中所有内容[返回的是迭代器]
a1 = re.finditer(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是10010")

for a in a1:
    print(a)
#     从迭代器中拿到内容需要.group()
    print(a.group())

<re.Match object; span=(8, 13), match='10086'>

10086

<re.Match object; span=(25, 30), match='10010'>

10010

re.search函数

搜索整个字符串,并返回第一个成功的匹配。

语法如下:re.search(pattern, string, flags=0)

pattern:需要匹配的正则表达式;

string:在那个字符串中就行匹配 ;

flags:标志位(默认为0),它可以控制正则表达式的匹配方式

常见的flags如下:

re.I 忽略匹配时的大小写

re.M 多行匹配,影响 ^ 和 $

re.S . 默认不匹配换行,使 . 匹配包括换行在内的所有字符

re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B

# 找到一个结果就返回
# search返回的结果是match对象,拿数据需要.group()
a2 = re.search(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是10010")
print(a2)
print(a2.group())

<re.Match object; span=(8, 13), match='10086'>

10086

re.match函数

match函数从头开始匹配,如果不是起始位置匹配成功的话,match函数的匹配结果就为none。匹配成功,re.match方法返回一个匹配的对象。

语法如下:re.match(pattern, string, flags=0)

pattern:需要匹配的正则表达式;

string:在那个字符串中就行匹配 ;

flags:标志位(默认为0),它可以控制正则表达式的匹配方式

常见的flags如下:

re.I 忽略匹配时的大小写

re.M 多行匹配,影响 ^ 和 $

re.S . 默认不匹配换行,使 . 匹配包括换行在内的所有字符

re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B

# match是从头开始匹配
a3 = re.match(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是10010")
print(a3)
# print(a3.group())

a4 = re.match(r"\d+","10086, 我女朋友的电话号码是10010")
print(a4)
print(a4.group())

None

<re.Match object; span=(0, 5), match='10086'>

10086

re.sub函数

在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串。

语法如下:re.sub(pattern, repl, string, count=0,flags=0)

pattern:需要匹配的正则表达式;

repl : 替换的字符串,也可为一个函数。

string:在那个字符串中就行匹配 ;

count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

flags:标志位(默认为0),它可以控制正则表达式的匹配方式

a = "我的电话号码是:10086, 我女朋友的电话号码是10010"

# sub 替换功能
a5 = re.sub(r"\d+",'tihuan520',a)
print(a5)

我的电话号码是:tihuan, 我女朋友的电话号码是tihuan

re.compile函数

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象。

语法如下:re.compile(pattern,flags=0)

pattern:需要匹配的正则表达式;

flags:标志位(默认为0),它可以控制正则表达式的匹配方式

obj = re.compile(r"\d+")

a6 = obj.findall("我的电话号码是10086,我女朋友的号码是10010")

print(a6)

['10086', '10010']

re.split函数

将一个字符串按照正则表达式匹配的结果进行分割,返回列表类型。

语法如下:re.split(pattern, string ,?maxsplit=0?,flags=0)

pattern:需要匹配的正则表达式;

string:在那个字符串中就行匹配 ;

maxsplit:分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。

flags:标志位(默认为0),它可以控制正则表达式的匹配方式。

a = "我的电话号码是:10086, 我女朋友的电话号码是10010"

# 通过数字分割
a7 = re.split(r"\d+",a)
print(a7)

['我的电话号码是:10086', ' 我女朋友的电话号码是10010']

模拟使用

import re

s = """
<div class='asd'><span id ='1'>周杰伦</span></div>
<div class='sad'><span id ='2'>撒大大</span></div>
<div class='afgdg'><span id ='3'>撒旦</span></div>
<div class='fdhfg'><span id ='4'>按时发放</span></div>
<div class='hfdh'><span id ='5'>复合肥</span></div>
"""
# re.S使其能够匹配换行符
obj = re.compile(r"<div class='.*?'><span id ='\d+'>.*?</span></div>",re.S)

result = obj.finditer(s)
for it in result:
    print(it.group())
输出:*(因为div会被吃掉,所以使用代码块)*

<div class='asd'><span id ='1'>周杰伦</span></div>
<div class='sad'><span id ='2'>撒大大</span></div>
<div class='afgdg'><span id ='3'>撒旦</span></div>
<div class='fdhfg'><span id ='4'>按时发放</span></div>
<div class='hfdh'><span id ='5'>复合肥</span></div>
import re

s = """
<div class='asd'><span id ='1'>周杰伦</span></div>
<div class='sad'><span id ='2'>撒大大</span></div>
<div class='afgdg'><span id ='3'>撒旦</span></div>
<div class='fdhfg'><span id ='4'>按时发放</span></div>
<div class='hfdh'><span id ='5'>复合肥</span></div>
"""
# (?P<分组名字>正则)可以单独从正则匹配的内容中进一步提取内容
obj = re.compile(r"<div class='.*?'><span id ='(?P<id>\d+)'>(?P<the>.*?)</span></div>",re.S)

result = obj.finditer(s)
for it in result:
    print(it.group("id"))
    print(it.group("the"))
输出:

1
周杰伦
2
撒大大
3
撒旦
4
按时发放
5
复合肥

实战案例

import requests
import re 

url = "https://movie.douban.com/top250"
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30'
}

resp = requests.get(url,headers=headers)

html = resp.text
# print(html.text)

# 先尝试取出标题

t = re.compile(r'<div class="info">.*?<span class="title">(?P<title>.*?)</span>',re.S)
               
result = t.finditer(html)
for s in result:
    print(s.group("title"))
输出:

肖申克的救赎
霸王别姬
阿甘正传
这个杀手不太冷
泰坦尼克号
美丽人生
千与千寻
辛德勒的名单
盗梦空间
忠犬八公的故事
星际穿越
楚门的世界
海上钢琴师
三傻大闹宝莱坞
机器人总动员
放牛班的春天
无间道
疯狂动物城
大话西游之大圣娶亲
熔炉
教父
当幸福来敲门
龙猫
控方证人
怦然心动
t = re.compile(r'<div class="info">.*?<span class="title">(?P<title>.*?)</span>.*?<p class="">(?P<dir>.*?)&nbsp',re.S)
               
result = t.finditer(html)
for s in result:
    print(s.group("title"))
    print(s.group("dir"))
    
输出:

肖申克的救赎

                            导演: 弗兰克·德拉邦特 Frank Darabont
霸王别姬

                            导演: 陈凯歌 Kaige Chen
阿甘正传

                            导演: 罗伯特·泽米吉斯 Robert Zemeckis
这个杀手不太冷

                            导演: 吕克·贝松 Luc Besson
泰坦尼克号

                            导演: 詹姆斯·卡梅隆 James Cameron
美丽人生

                            导演: 罗伯托·贝尼尼 Roberto Benigni
千与千寻

                            导演: 宫崎骏 Hayao Miyazaki
辛德勒的名单

                            导演: 史蒂文·斯皮尔伯格 Steven Spielberg
盗梦空间

                            导演: 克里斯托弗·诺兰 Christopher Nolan
忠犬八公的故事

                            导演: 莱塞·霍尔斯道姆 Lasse Hallström

———————————————————————————————————————————————————————————————————————————————————————————————
(过于长,省略一部分的显示)
# 发现导演前面有多余空格,是因为原html中有换行
t = re.compile(r'<div class="info">.*?<span class="title">(?P<title>.*?)'
               r'</span>.*?<p class="">(?P<dir>.*?)'
               r'&nbsp.*?<br>(?P<year>.*?)'
               r'&nbsp.*?&nbsp;/&nbsp;(?P<types>.*?)'
               r'</p>.*?<span property="v:best" content="(?P<score>.*?)'
               r'"></span>.*?<span>(?P<nums>.*?)'
               r'</span>.*?<span class="inq">(?P<eva>.*?)</span>',re.S)
               
result = t.finditer(html)
for s in result:
    print(s.group("title"))
    
# Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
# 注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。
    print(s.group("dir").strip())
    print(s.group("year").strip())
    print(s.group("types").strip())
    print(s.group("score"))
    print(s.group("nums"))
    print(s.group("eva"))
    
    print('-------------------------------------')
输出:

肖申克的救赎
导演: 弗兰克·德拉邦特 Frank Darabont
1994
犯罪 剧情
10.0
2475478人评价
希望让人自由。
-------------------------------------
霸王别姬
导演: 陈凯歌 Kaige Chen
1993
剧情 爱情 同性
10.0
1840107人评价
风华绝代。
-------------------------------------
阿甘正传
导演: 罗伯特·泽米吉斯 Robert Zemeckis
1994
剧情 爱情
10.0
1860233人评价
一部美国近现代史。
-------------------------------------
这个杀手不太冷
导演: 吕克·贝松 Luc Besson
1994
剧情 动作 犯罪
10.0
2023880人评价
怪蜀黍和小萝莉不得不说的故事。
-------------------------------------
———————————————————————————————————————————————————————————————————————————————————————————————
(过于长,省略一部分的显示)

保存文件

import csv 

t = re.compile(r'<div class="info">.*?<span class="title">(?P<title>.*?)'
               r'</span>.*?<p class="">(?P<dir>.*?)'
               r'&nbsp.*?<br>(?P<year>.*?)'
               r'&nbsp.*?&nbsp;/&nbsp;(?P<types>.*?)'
               r'</p>.*?<span property="v:best" content="(?P<score>.*?)'
               r'"></span>.*?<span>(?P<nums>.*?)'
               r'</span>.*?<span class="inq">(?P<eva>.*?)</span>',re.S)
               
result = t.finditer(html)

f = open("data.csv",mode='w',encoding='utf-8')
csvwrite = csv.writer(f)

for s in result:
    print(s.group("title"))
    dic = s.groupdict()
    dic['dir']=dic['dir'].strip()
    dic['year']=dic['year'].strip()
    dic['types']=dic['types'].strip()
#     print(dic)
    csvwrite.writerow(dic.values())
    

f.close()   
#      print(s.group("dir").strip())
#     print(s.group("year").strip())
#     print(s.group("types").strip())
#     print(s.group("score"))
#     print(s.group("nums"))
#     print(s.group("eva"))
    
#     print('-------------------------------------')
肖申克的救赎
霸王别姬
阿甘正传
这个杀手不太冷
泰坦尼克号
美丽人生
千与千寻
辛德勒的名单
盗梦空间
忠犬八公的故事
星际穿越
楚门的世界
海上钢琴师
三傻大闹宝莱坞
机器人总动员
放牛班的春天
无间道
疯狂动物城
大话西游之大圣娶亲
熔炉
教父
当幸福来敲门
龙猫
控方证人
怦然心动

读取文件检查一下

import pandas as pd

titanic_data = pd.read_csv('data.csv')

titanic_data.head()

image.png