一:环境
---------
操作系统 : Windows10
Python版本 : Python 3.6.4
IDE : Pycharm
所需模块 : requests,urllib
二:爬取网址
----------
Unsplash : https://unsplash.com/
三:分析过程
----------
要爬取一个网站,我们首先想的就是分析该网页,通过浏览器的查看元素,我们能够很容易的看到该网页的源码,我们随便在一张图片上单击右键,查看该图片在源码中的位置。
在图中,我们可以看到我们所需要的图片所在的节点,这是一个img标签的节点,里面有我们所需要的图片的位置。
我们捋一下思路,显然我们要做的步骤如下:1:对网页进行解析 2:提取出图片的路径 3:访问路径进行下载
然而事实并没有这么简单,仔细看看,我们会发现,网页源码中只有为数不多的几个img标签,也就是说,我们只能获取到几张图片的路径,我们要的可是大量的图片,接下来将页面下滑,会发现img标签多了起来,很显然这是一个Ajax[1]动态加载的网站,抓包分析,可以看到响应中的是json[2],在json中我们可以找到11张需要的图片的路径信息。
选定其中一个请求,分析它的参数信息。可以发现,这是一个GET类型的请求,请求网址为https://unsplash.com/napi/photos?page=5&per_page=12&order_by=latest,在这url中,我们看到了 https://unsplash.com/,这个是我们请求网站的网址,那后面的东西是啥?别急,我们接着看,"page=5" 应该是第五页的意思,是个变化的值,"per_page=12" 是个固定的参数,"order_by=latest" 也是个固定的参数,所以捋一下思路,我们只要构造page这个参数,然后用循环遍历每一页,就能获取到所有的json数据了,现在你或许胸有成竹了,以为稳操胜券???
然而,当我们访问图片路径时,貌似并没有得到我们想要的结果,我们看一下http请求,什么?302。。。被重定向了,有点意思,知道了问题所在,该如何解决呢?我们可以给requests.get方法中加一个参数,allow_redirects,这个参数默认为True,我们可以改为allow_redirects=False,不允许其重定向。然后,我们就可以获取到它的真实下载路径。
response=requests.get(url,headers=headers,allow_redirects=False)
photo_url_download = response.headers['Location']
至此,我们算是解决了所有的问题,接下来,我们要开始撸代码了。
四:实际操作
---------
我们先将初始信息写下,这里的初始信息主要是一些url,以及一些headers信息,这在我们后面会用到。
import requests
from urllib.parse import urlencode
#初始信息
NUMBER_OF_PHOTO=100
base_url='https://unsplash.com/napi/photos?'
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0',
'X-Requested-With':'XMLHttpRequest',
'Referer':'https://unsplash.com/',
'Host':'unsplash.com',
'Connection':'keep-alive'
}
然后,我们得获取json数据,这里我用requests库,然后从中解析出id,将其组装成图片的下载路径,然后向此路径发送请求,获取重定向后的真实下载路径,再次对真实下载路径发送请求。
#解析一个页面的json
def json_parse(page):
params = {
'page': str(page),
'per_page': '12',
'order_by': 'latest'
}
url = base_url + urlencode(params)
response = requests.get(url, headers=headers)
if response.status_code == 200:
json = response.json()
photo_url_download_true=[]
photo_id=[]
data=[]
for i in range(len(json)):
photo_url_id = json[i].get('id')
#print(photo_url_id)
photo_url_download = 'https://unsplash.com/photos/' + photo_url_id + '/download?force=true'
#获取重定向后的url
response1 = requests.get(photo_url_download, headers=headers, allow_redirects=False)
photo_url_download = response1.headers['Location']
photo_url_download_true.append(photo_url_download)
photo_id.append(photo_url_id)
data.append(photo_url_download_true)
data.append(photo_id)
return data
else:print('获取重定向后的url失败')
接下来,我们将获取到的图片数据写入文件,这里,我们构造一个写入文件的函数。
#将照片写入文件
def write_to_file(photo_url_download_true,id,page,number):
response2 = requests.get(photo_url_download_true)
if response2.status_code == 200:
file_path = "e:/Unsplash/" + id + ".jpg"
with open(file_path, 'wb') as f:
f.write(response2.content)
print('正在下载第%d张照片.....' % (page*11+number+1))
print(id + ".jpg" + '下载成功')
else:
print('下载失败')
现在,我们的大部分代码就完成了,我们将剩余代码完成。当然,为了更加完善和完整,我还给代码加了一个计算函数。
#计算函数
def calc():
page=(NUMBER_OF_PHOTO -1)// 12
number=NUMBER_OF_PHOTO -page*12
return [page,number]
#主函数
def main():
pages=calc()[0]
numbers=calc()[1]
for page in range(pages):
print('********************请耐心等待********************')
data = json_parse(page)
for count in range(12):
write_to_file(data[0][count],data[1][count],page,count)
print("********************请耐心等待********************")
data=json_parse(pages)
for number in range(numbers):
write_to_file(data[0][number],data[1][number],pages,number)
if __name__=='__main__':
main()
终于,大功告成。
最后,效果图摆上。
源码: https://github.com/kingdowliu/Unsplash_Spider/blob/master/unsplash.py
[1]Ajax: Ajax 是一种用于创建快速动态网页的技术,是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术,通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
[2]json: json是一种轻量级的数据交换格式,通过数组与对象的组合来表示数据。在 JS 语言中,一切都是对象。因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型。