本文以抓取“斗图啦”(http://www.doutula.com/)中的图片为例来介绍如何使用python和正则表达式完成最基本的爬虫和文件下载工作。
进入网站后,点击最新表情,并点击第二页,网页的url(http://www.doutula.com/photo/list/?page=2)同样发生了变化。不难发现,此网页的请求方式为最简单的get请求。
Python资源共享群:484031800
下面,我们将使用requests、re、os库来实现图片的抓取与下载。
一、导入python标准库
这里我们将用到三个标准库,os用来创建文件夹并更改缺省路径;requests用来抓取网页源代码;re用来提取源代码中我们需要的信息。
import os import reimport requests
二、创建文件夹并更改缺省路径
os.mkdir(r"D:/斗图") #在D盘创建“斗图”文件夹,如果文件夹存在则会报错。os.chdir(r"D:/斗图") #更改缺省路径到"D:/斗图"。os.getcwd() #查看缺省路径是否已经更改。
三、构建headers,抓取网页源代码
首先,我们构建一个名为headers的字典,并传给requests.get()中的headers参数,requests将该参数作为请求报文的首部字段编制报文,字典headers中可以传入请求头的部分信息以防止网站反爬。那么,headers字典中的参数是从哪里得到的呢?参考爬虫俱乐部往期推文《一起来揪出网页真实链接!》,找到网页的一些请求头:即下图的Headers。
我们使用几个重要参数构建字典,程序如下:
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36', 'Host': 'www.doutula.com' }
我们在这里设定字典中的两个key分别是User-Agent、Host,当然,请求头中的其他参数也可根据需求添加到字典中。接下来,使用requests.get()方法抓取网页源代码,程序如下:
response = requests.get("http://www.doutula.com/photo/list/?page=1",headers = headers)print(response.text)text = response.text
requests.get()方法中的第一个参数是url,此参数是必须传入的一个参数。此外,此方法中还有一些其他参数,例如:headers,传入请求头信息;proxies,传入代理地址;params,传入get请求的参数,例如“http://www.doutula.com/photo/list/?page=1”,get请求方式如果以“?”携带参数,可将参数“page=1”构建成字典传给params,此时requests.get()中传入的url则变成“http://www.doutula.com/photo/list/”。
打印网页源代码,发现python为我们解析出的网页源代码无乱码,可直接使用text变量来接收网页源代码。
四、使用正则表达式提取信息 部分网页源代码如下:
“data-original”属性的值就是图片的地址,而p标签中存放的则为图片名称,我们的目的就是利用图片的url将图片下载下来,将下载下来的文件名设定为图片原本的文件名,因此我们需要提取url和图片名。
首先使用re.findall方法将图片的url和名称提取出来,此方法第一个需要传入的参数为正则表达式,第二个参数为目标字符串,第三个参数re.S的作用是使正则表达式将目标字符串作为一个整体,将“\n”当做一个普通的字符加入到这个字符串中,使“.“能够匹配换行符,而无须在匹配之前将目标字符串中的空字符剔除。
imgs_url_name = re.findall('data-original="(.*?)".*?(.*?)',text,re.S) re.findall方法可直接将子表达式中包含的内容提取出来。
print(imgs_url_name)len(imgs_url_name) 结果如下:
可以发现,findall方法返回一个列表,列表中的每一个元素都是一个元组,元组中的每条信息就是子表达式匹配到的内容。关于re库更详细的用法可参考爬虫俱乐部往期推文《Python标准库re:正则表达式》。
五、下载图片
这一步需将上边获取到的url和图片名称使用切片提取出来并使用requests.get()方法和文件操作的方法将图片下载到本地。程序如下:
for img in imgs_url_name: #img是包含图片url和名称的元组 name = img[1] #提取图片名称 name = re.sub(r'[\??\.,。!! /]','',name) #将图片名称中的一些不适合作为文件名的符号剔除。 #print(name) url = img[0] #提取图片url #print(url)suffix = os.path.splitext(url)[1] #提取图片后缀
os.path.splitext()方法可分离文件名与扩展名,默认返回元组。例如,“http://img.doutula.com/production/uploads/image//2019/07/01/20190701929023_ZBfzXo.jpg“可分离成”http://img.doutula.com/production/uploads/image//2019/07/01/20190701929023_ZBfzXo“和“.jpg”.
#print(suffix) filename = name + suffix #使用图片名称和后缀构造文件名print(filename)#获取每张图片的源代码,并将其以二进制形式写入文件。 r = requests.get(url) with open(filename,"wb") as fp : fp.write(r.content)
有了这些图片,你就是斗图界的专家啦!
以 上是爬取单个页面的程序,如果我们想爬取多个页面,只需要对页码循环,并更改url中参数page的 值即可,完整程序如下:
import os import reimport requests os.mkdir(r"D:/斗图")os.chdir(r"D:/斗图")os.getcwd() headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36', 'Host': 'www.doutula.com' }for page_num in range(1,5) : response = requests.get("http://www.doutula.com/photo/list/?page={}".format(page_num),headers = headers) print(response.text) text = response.text imgs_url_name = re.findall('data-original="(.*?)".*?(.*?)',text,re.S) print(imgs_url_name) len(imgs_url_name) for img in imgs_url_name: name = img[1] name = re.sub(r'[\??\.,。!!/ ]','',name) print(name) url = img[0] print(url) suffix = os.path.splitext(url)[1] print(suffix) filename = name + suffix print(filename) r = requests.get(url) with open(filename,"wb") as fp : fp.write(r.content)