python爬虫演绎正则提取数据
1.什么是正则表达式?
2.爬取《男人装》网页内容
-
这次我们来抓取《男人装》杂志的网页中一些我们需要的内容
- 浏览器搜索男人装,进入官网,随便进入一个页面:
- 获取页面的url
-
第一步请求服务器响应的数据
这次我们要用到urllib库里面的request模块
from urllib import request
url = 'http://enrz.com/fhm/2016/12/17/74914.html'
""" 请求服务器,获得服务器响应的数据"""
req = request.Request(url)
html = request.urlopen(req)
content = html.read().decode('utf-8')
print(content)
此时我们获取到了这些数据:
- 第二步解析数据提取数据内容
我们来实现这样一个功能:爬取网页数据,存储到文件夹里面,网页每个标题对应一个文件夹。- 这里我们要用到正则表达式的通配符
- 1.什么是正则表达式?
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。——《百度百科》
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
①. 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”):
②. 可以通过正则表达式,从字符串中获取我们想要的特定部分。
- 简单来说,打个比方:
假设这里有一篇xxx的自我介绍,我们想从中了解xxx的兴趣爱好,那么我们可以在文章中找结构为 “我喜欢{xxx}” 或者 “我爱好{xxx}” 的句子,然后提取出{ }里面的内容,这就是对字符串的过滤。
正则表达式使用方法:
- 正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。
举几个例子:
- 最简单的元字符是点,能够匹配任意的单个字符 下面语句:①he is in a rat ②I like root beer ③the food is Rotten
- 正则表达式 r.t 匹配① ,它是区分大小写的,如果要同时匹配大写和小写可以这么写: [Rr].t
这里我们用的是通配符
通配符是一类键盘字符。
当查找文件夹时;当不知道真正字符或者不想键入完整名字时,常常使用通配符代替一个或多个真正字符。
星号( * )
可以使用星号代替零个、单个或多个字符。如果正在查找以AEW开头的一个文件,但不记得文件名其余部分,可以输入AEW*,查找以AEW开头的所有文件类型的文件,如AEWT.txt、AEWU.EXE、AEWI.dll等。要缩小范围可以输入AEW*.txt,查找以AEW开头的所有文件类型并.txt为扩展名的文件如AEWIP.txt、AEWDF.txt。
问号( ?)
可以使用问号代替一个字符。如果输入love?,查找以love开头的一个字符结尾文件类型的文件,如lovey、lovei等。要缩小范围可以输入love?.doc,查找以love开头的一个字符结尾文件类型并.doc为扩展名的文件如lovey.doc、loveh.doc。
通配符包括星号“ * ”和问号 “ ?”
星号表示匹配的数量不受限制,而后者的匹配字符数则受到限制。 这个技巧主要用于英文搜索中,如输入““computer*”,就可以找到“computer、computers、computerised、computerized”等单词,而输入“comp?ter”,则只能找到“computer、compater、competer”等单词。
——《百度百科》
这里我们用组合字符(.*?)
- 当(.*?)带有小括号时表示是我们需要获取的内容, . * ?不带小括号时表示不需要的内容。
使用正则表达式,我们需要导入re模块
import re
下面我们来提取数据
第一步构造用于过滤的字符串
1.标题
在网页查看源代码,找到标题的格式:
'<div id="content">
<h2>如何系围巾不显得娘炮?</h2>'
- 用(.*?) 取代我们需要的内容, 特别提出一点的是不要忘了源代码中< h2>前还有一个换行符
title_pattern = '<div id="content">.*?<h2>(.*?)</h2>'
2.网页中的图片:
<p><img class=" size-full wp-image-74915 aligncenter" src="http://images.enrz.com/wp-content/uploads/2016/12/FAKE-KNOT-1.jpg" alt="fake-knot-1" width="218" height="354" /></p>
我们需要src里面的内容,忽略掉其他的标签属性(这里保留class特征取得网页中的大图)
url_pattern = '<p><img class=.*?src="(.*?)".*?/></p>'
第二步将两个字符串转换为正则表达式对象
"""加载成为正则表达式对象"""
title = re.compile(title_pattern,re.S)
"""在获得的字符串中匹配我们所需要的内容"""
title_result = re.search(title,content)
print(title_result.group(1))
*(re.S使得表达式能够匹配包括’\n’的所有字符)
下面是我们的运行结果:
第三步动态地建立文件夹
- 导入os模块
import os
- 拼接当前文件夹地绝对路径新建文件名,以之新建文件
dir_path = os.path.join ( os.getcwd(), namestr)
if not os.path.exists (dir_path):"""如果该文件夹不存在则新建"""
os.makedirs (dir_path)
运行结果:该目录下新生成文件夹
第四步爬取内容(图片)
- 当前页面有多张图片,通过死循环抓取
pic_url = re.compile(url_pattern,re.S)
while True:
pic_items = re.findall( pic_url, content )
print(pic_items)
break
运行结果:爬取到了该页面地图片链接
再加上存储的操作:
- 图片的名称的获取需要再次用到通配符:
^ 匹配输入字行首。
$ 匹配输入行尾。
http://images.enrz.com/wp-content/uploads/2016/12/FAKE-KNOT-1.jpg
- 我们需要的内容:
FAKE-KNOT-1.jpg
- 从匹配到的图片链接中逐个匹配图片名称
pic_url = re.compile(url_pattern,re.S)
name_pattern = '^.*/(.*?)$'
last_pic_name= re.compile(name_pattern,re.S)
while True:
pic_items = re.findall( pic_url, content )"""查找content里面所有满足条件的图片url"""
for item in pic_items:
name_result = re.search(last_pic_name, item)"""获取每一个url的图片名称"""
name = name_result.group(1)
print(name)
break
运行结果:获得了所有图片的名称
- 将图片存入文件夹
pic_path = os.path.join(dir_path,name)"""获得每一张图片的路径"""
req = request.Request(item)"""向服务器请求获取图片数据"""
html = request.urlopen(req)
data = html.read()
with open(pic_path, 'wb') as file:"""将图片存入文件夹"""
file.write(data)
运行结果: 爬取到了改也没所有的图片
源代码:
from urllib import request
import re
import os
from urllib.parse import quote
import string
url = 'http://enrz.com/fhm/2016/12/17/74914.html'
""" 请求服务器,获得服务器响应的数据"""
req = request.Request(url)
html = request.urlopen(req)
content = html.read().decode('utf-8')
title_pattern = '<div id="content">.*?<h2>(.*?)</h2>'
url_pattern = '<p><img.*?src="(.*?)".*?/></p>'
name_pattern = '^.*/(.*?)$'
"""加载成为正则表达式对象"""
title = re.compile(title_pattern,re.S)
"""在得到的字符串中匹配我们所需要的内容"""
title_result = re.search(title, content)
namestr = title_result.group(1)
dir_path = os.path.join(os.getcwd(), namestr)
if not os.path.exists(dir_path):
os.makedirs(dir_path)
pic_url = re.compile(url_pattern, re.S)
last_pic_name = re.compile(name_pattern, re.S)
while True:
pic_items = re.findall(pic_url, content)
for item in pic_items:
name_result = re.search(last_pic_name, item)
name = name_result.group(1)
pic_path = os.path.join(dir_path,name)
url = quote(item, safe=string.printable)
req = request.Request(url)
html = request.urlopen(req)
data = html.read()
with open(pic_path, 'wb') as file:
file.write(data)
break