大数据 > 手把手教你用 Python 爬取美女图

手把手教你用 Python 爬取美女图

2019-09-10 14:00阅读(59)

" 最近由于公司业务的需要,我开始做了一些简单的爬虫的工作。学了爬虫之后,就在想,能不能用爬虫做一些有趣的事情呢?想来想去,还是教大家写个简单的爬虫,用

1
"

最近由于公司业务的需要,我开始做了一些简单的爬虫的工作。学了爬虫之后,就在想,能不能用爬虫做一些有趣的事情呢?想来想去,还是教大家写个简单的爬虫,用来爬取一组美女图。

因为只有美女图才能吸引你们这些绅士过来围观。。。。。

最后附上源码,拿去直接就可以用了。

目标

我在 bing 上搜索 美女图,出来了这个。

手把手教你用 Python 爬取美女图

那我们就用这个来开刀吧。

手把手教你用 Python 爬取美女图

额。。。。。。。。

这尺度,我们还是选个保守一点的来做例子吧。。。。。。

手把手教你用 Python 爬取美女图

配置环境

由于我们是使用 python 来做爬虫的,所以我们要先装好 python 环境,这个比较简单,直接到官网下载安装就可以了,安装的过程也是一直下一步就行。

下载地址: https://www.python.org/downloads/

手把手教你用 Python 爬取美女图

我们选择相应的操作系统平台安装就可以了。

还有一个是 python 的网络请求库 requests ,我们后面将要使用这个库进行网络请求,来爬取数据。

这个库的安装也很简单,在命令行下执行以下命令就可以了

pip3 install requests

还有一个是用来解析 html 结构,和提取元素内容的一个库。安装也很简单

pip3 install beautifulsoup4

开始分析

在 Chrome(谷歌浏览器) 下,打开我们要爬取的地址 https://www.walltu.com/tuku/201801/212736.html , 然后按 F12 ,在网络这一栏,我们可以看到这个页面的请求。

手把手教你用 Python 爬取美女图

然后,再切到 XHR 下,发现这个页面并没有发 ajax ,也就是说,我们要爬取的图片地址和页面可能是在一起的。

我们看一下这个 html 页面里面是什么东西。

手把手教你用 Python 爬取美女图

然后我们在使用元素选择器,看一下我们要爬取的图片是哪个元素,然后我们再到 html 代码里面找一下,找到这个图片的元素

手把手教你用 Python 爬取美女图

找到了,然后我们再到网络请求到页面里面看一下,看能不能找到这个元素,果然找到了。

手把手教你用 Python 爬取美女图

我们再浏览器直接打开这个地址:

手把手教你用 Python 爬取美女图

那就说明可以通过地址直接获取到图片,那我们就开始了。

开始干活

到这里,我们就要开始正式写代码了,但是不要担心,很简单的。老司机带路肯定是稳的!

先从下载图片开始

我们先试一下,看能不能直接请求到图片。打印一下请求的状态码和内容。

import requests
response = requests.get('https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800')
print(response.status_code)
print(response.content)

打印结果如下:

403
b'{"code":"40310014","msg":"invalid Referer header"}'

请求失败了,但是提示我们 referer 非法。说起来也是挺好笑的,居然会提示我们错误的地方,这是怕我们爬不到数据吗。。。。。。

知道问题在哪就好搞了。我们找一下这个信息要填什么。

切换之前页面的调试界面,选中 img ,看一下页面上请求时用的是什么,照抄过来就行了。

手把手教你用 Python 爬取美女图

然后把这个东西加到请求头试一下

import requests
headers = {
'Referer':'https://www.walltu.com/tuku/201801/212736.html'
}
response = requests.get('https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800',headers=headers)
print(response.status_code)
print(response.content)

上面的代码应该很容易看懂吧,即使没有学过 python 。就是在请求的时候多添加了一个请求头的参数

打印内容如下:

200
b'xffxd8xeaxe3ox88...............1x12xc1x1bx19)xbcwx139ux0eLDxd8lx02ox81x12c&xc4xc9xf2MTx7fxffxd9'

我们看到状态码是 200 ,说明成功了,后面打印的是图片的二进制数据,由于图片转化成二进制内容很多,中间的部分信息被我省略了。

保存图片

刚才我们通过 requests 请求到了图片,但是二进制的图片给我们没有用啊,我们要看图片,真正的图片!

那我们就要把图片保存起来。我们先打开一个文件,然后把请求到的内容写入到文件里面就行了。

import requests
headers = {
'Referer':'https://www.walltu.com/tuku/201801/212736.html'
}
response = requests.get('https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800',headers=headers)
# 打开一个文件,第一个参数是文件路径,第二参数是打开方式,'wb' 表示以二进制写入的方式打开
img_file = open('img.jpg','wb')
# 然后往文件里面写内容
img_file.write(response.content)

这段代码执行完,应该就可以在同个目录下找到下载好的 img.jpg 图片,打开就能看见下载好的图片的了。是不是很简单呢。

目标是爬取一组图

我们搞半天,只是把一张图片下载到本地而已,这么麻烦,还不如直接在页面上右击保存图片来得快呢。。。。。。

我们的目标可不是下载一张图片,而是一整组图片!

从第一张图片开始爬取

第一张图片刚才不是下载完了?

不不不,我们要是输入这一组图片的网页地址,就可以下载这一组图片的效果。也就是输入 https://www.walltu.com/tuku/201801/212736.html 就可以下载一整组图的效果。

要实现这个效果,可就不能像之前那样手动去找图片的地址了,要通过代码找到图片的地址。那我们就需要使用一些工具来帮我们找到这个地址了,我这里使用的是 BeautifulSoup 来进行元素查找。

我们先看一下刚才查找的那个图

手把手教你用 Python 爬取美女图

观察这个结构,发现比较靠近目标并且有特点的元素是 <ddclass="p"> ,我们只要找到这个元素,再顺藤摸瓜,往下找到下面的 <p> 然后再往里面就可以找到我们要的 <img> 这个元素了。

手把手教你用 Python 爬取美女图

代码上,我们可以这么写:

import requests
from bs4 import BeautifulSoup
# 请求这个页面
response = requests.get('https://www.walltu.com/tuku/201801/212736.html')
# BeautifulSoup 的构造函数最少需要两个参数,第一个是要解析的内容,第二个是解析器,这里我们使用的是 'html.parser'
content = BeautifulSoup(response.content, 'html.parser')
target_parent = content.find('dd', class_='p')
target = target_parent.p.img
img_address = target['src']
print(img_address)

打印结果如下:

https://img.walltu.com/d/file/shutu/2018-01/20150813115821611.jpg!800

我们这样就拿到了第一个页面的图片地址。

查找下一个

我们的最终目标的是爬取一整组图。找到了第一个图片,那就要准备找下一个了。

手把手教你用 Python 爬取美女图

我想很多人想到的是图片右边的 下一图 这个按钮,但是有个问题,就是到这组图的最后一张后,这个按钮的链接就会变成下一组图的地址了,这样就会一直循环下去,这可不行。

我把目标转到了下面。

手把手教你用 Python 爬取美女图

我们发现当前的图片是有个选中的样式的,我们应该可以找到这个元素,然后找到下一个元素,也就是下一个图片的页面的链接。这个会不会有最后一张的地址变成下一组的地址 这个问题呢?

我们看一下:

手把手教你用 Python 爬取美女图

好像没有,最后一个还是最后一个,没有多出一个是跳下一组图的元素。我们还得看一下 html 。

手把手教你用 Python 爬取美女图

确实没有一些多余的东西,而且我们还发现了选中的样式是 class="c",那就开始干活!

import requests
from bs4 import BeautifulSoup
# 请求这个页面
response = requests.get('https://www.walltu.com/tuku/201801/212736.html')
# BeautifulSoup 的构造函数最少需要两个参数,第一个是要解析的内容,第二个是解析器,这里我们使用的是 'html.parser'
content = BeautifulSoup(response.content, 'html.parser')
# 找到当前选中的图片
index = content.find('a', class_='c')
# 找到下一个图片的元素
next_target = index.next_sibling
if next_target is None:
# 没有下一个了
print('没有下一个了')
else:
# 找到了下一个,我们就打印出来
print('下一个')
next_addr = 'https://www.walltu.com' + next_target['href']
print(next_addr)

打印结果:

下一个
https://www.walltu.com/tuku/201801/212736_2.html

如果是最后一个呢?我们也看一下,我们把地址换成 https://www.walltu.com/tuku/201801/212736_7.html

再执行一次,打印结果

没有下一个了

再配合上之前下载图片的代码,应该就可以把一整组图给下载下来了。我们还需要一个文件夹把这些图片给整理放好,其实还有剩下的两步工作,就是新建一个文件夹,用来存放图片,然后下载图片的时候再给每个图片命名,否则重复的文件名会把之前的图片给覆盖掉。

新建文件夹

新建文件夹很简单

import os
# 创建文件夹
os.makedirs('文件夹的名称')

用来存图片的目录名就用第一个页面的标题吧。

给图片命名

要给图片命名,就要考虑唯一性,从图片的下载地址上看,这些名称确实是唯一的,但是都是一些随机的名称,也就是没有顺序,感觉也不太好,因为这些图片实际上是有一定顺序的。

实在不行,那就用页面的地址吧。因为一个图片对应的也是一个页面,而且我们看一下这些页面地址。

https://www.walltu.com/tuku/201801/212736.html
https://www.walltu.com/tuku/201801/212736_2.html
https://www.walltu.com/tuku/201801/212736_3.html
https://www.walltu.com/tuku/201801/212736_4.html

我们发现,这些还是有顺序的,刚好满足我们的需求。

在下载图片的时候,传入名称就行了。这里就不上代码了。

整理一下思路

    根据第一个页面的标题新建一个文件夹,用来存放图片。解析页面,下载第一张图片,获取下一个页面的地址循环第二步,直到下载完最后一个图片。

整理一下代码

我们最后整理一下代码,把一些操作抽取成方法。

import os
import requests
from bs4 import BeautifulSoup
# 下载所有图片
def downloadAllImg(address):
# 解析页面
content = getContent(address)
# 获取页面标题
title = content.title.string
# 新建文件夹
os.makedirs(title)
# 获取图片的地址
download_img_addr = getDownloadImgAddr(content)
# 获取文件名
file_name = getFileName(address)
print('开始下载:'+title)
while download_img_addr is not None:
# 下载图片
downloadImg(download_img_addr,address,title,file_name)
# 获取下一个页面的地址
next_addr = getNextAddr(content)
if next_addr is None:
download_img_addr = None
else:
# 获取下一个图片的名称,并赋值给 变量
file_name = getFileName(next_addr)
# 解析下一个页面,并赋值给 变量
content = getContent(next_addr)
# 获取下一个图片的下载地址,并赋值给 变量
download_img_addr = getDownloadImgAddr(content)
print('新下载地址:'+download_img_addr)
print('已全部下载完成')
# 解析页面
def getContent(address):
response = requests.get(address)
return BeautifulSoup(response.content, 'html.parser')
# 获取图片的地址
def getDownloadImgAddr(content):
target_parent = content.find('dd', class_='p')
target = target_parent.p.img
img_address = target['src']
return img_address
# 获取下一个页面的地址
def getNextAddr(content):
index = content.find('a', class_='c')
next_target = index.next_sibling
if next_target is None:
print('没有下一个了')
return None
else:
print('下一个')
next_addr = 'https://www.walltu.com' + next_target['href']
print(next_addr)
return next_addr
# 获取文件的名称
def getFileName(address):
end_index = address.rfind('.')
start_index = address.rfind('/')
return address[start_index + 1:end_index]
# 下载图片
def downloadImg(imgAddress,fromAddr,dir,file_name):
print('正在下载:'+file_name)
img = open(dir+'/'+file_name+'.jpg', 'wb')
headers = {
'Referer': fromAddr
}
img_response = requests.get(imgAddress, headers=headers)
img.write(img_response.content)
img.close()
print('下载完成:'+imgAddress)
# 调用,传入要下载的图片的地址
downloadAllImg('https://www.walltu.com/tuku/201801/212736.html')

代码到这里就完成了,想要下载其他组图,只要换一下,最后调用的地址就可以了。

最后,我们看一下效果吧。成功下载到了一整组图。

手把手教你用 Python 爬取美女图

大家快去试一下吧!

"