美文网首页
异步 & ajax | 下载unplash高清大图

异步 & ajax | 下载unplash高清大图

作者: 0与1的邂逅 | 来源:发表于2019-04-26 23:48 被阅读0次

    写在前面:

    第一篇关于爬虫的文章,主要涉及异步操作带ajax网页的分析。

    • 操作系统:win10
    • IDE:VS Code
    • Python 3.6
    • 异步库:asyncio
    • 异步请求库:aiohttp
    • 同步请求库:urllib、requests
    • 其他相关库:os、time

    这里限于篇幅原因,可能无法对每一行代码进行详细的剖析,在后面的文章中,我也将不断地总结、记录一些python库地用法。

    大家都知道,python的第三方库正在不断地扩大,因此,对于常用库的积累和对相应库的学习,都是非常重要的。(在我看来,自己造轮子挺不现实的)


    Ajax是什么?

    AjaxA synchronous Javascript And XML(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。

    Ajax = 异步 JavaScript 和 XML 或者是 HTML(标准通用标记语言的子集)。

    Ajax 是一种用于创建快速动态网页的技术。

    Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

    通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

    传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。

    ——《百度百科》

    关键一点:Ajax请求的文件格式是XHR

    举例子说,当你访问unplash的时候,往下滑动图片,你会发现在你滑动的过程中,有些图片还没加载出来,需要等待一小段时间,这些图片就是通过Ajax加载的。

    关于Ajax的更多信息,可以看一下崔庆才大佬的博客:


    1. 分析并访问Ajax:

    (因为用的是火狐浏览器,所以开发者选项是中文的,不过还是建议用谷歌浏览器)

    首先,按下F12,打开开发者选项,选中Network(网络)这一项。一开始,当我们还为向下滑动鼠标时,只显示了一个get请求,如下图。

    当我们开始向下滑动鼠标的时候,下方的图片开始通过Ajax加载出来,生成许多的CSS、JS等格式的文件。而我们知道Ajax的文件格式是XHR,可以通过选择器选择仅显示XHR的文件,方便我们分析。

    未使用选择器 使用选择器筛选 我们多向下滑动几次,请求到更多的Ajax,以便发现其规律。

    可以看到,这些Ajax的请求头都有两个参数, page和per_page。

    page表示第几页,per_page表示每一页有多少张图片。

    通过对比,我们发现只有page这个参数在变,而per_page一直等于12。因此,我们仅需要改变page参数的值,就可以访问到不同的Ajax。

    这里主要的难点是如何构造出URL中特定的参数,这里主要有两种方式,一种是利用urllib中的urlencode(),另一种是requests中的params参数。

    【requests的params参数】
       # 对ajax进行请求,返回JSON响应
       def __get_img_links(self, page):
           url = 'https://unsplash.com/napi/photos'
           data = {
               'page': page,
               'per_page': 12,
           }
           response = requests.get(url, headers=self.headers,params=data)
           if response.status_code == 200:
               return response.json()
           else:
               print(f'请求失败,状态码为{response.status_code}')
    
    【urllib的urlencode()函数】
    import requests
    from urllib.parse import urlencode
    
    def __get_img_links(self, page):
        params = {
             'page': page,
             'per_page': 12,
        }
        url = 'https://unsplash.com/napi/photos/?' + urlencode(params)
        response = requests.get(url,headers=self.headers)
        if response.status_code == 200:
            return response.json()
        else:
            print(f'请求失败,状态码为{response.status_code}')
    

    2. 分析Ajax返回的JSON响应

    我们可以在开发者选项中响应中查看返回的JSON响应。


    也可以将其中一个Ajax的请求在新的标签页中打开,如下图。我个人是比较喜欢在新的标签页中打开,然后进行分析。(主要是受网页大小的限制) 既然已经获得了JSON的信息,我们开始对其进行分析,找到我们需要的信息,如下图。

    这里,我们仅需要图片的ID和下载链接这两个信息。

    • ID作为图片的文件名
    • 下载链接用于下载图片

    至此,对unplash这个网页的Ajax分析就已经完成了,接下来就是代码实现了。

    3. 代码实现

    import requests, os, time
    import aiohttp, asyncio
    
    class Spider(object):
       # 初始化
       def __init__(self):
           self.headers = {
               'Referer':'https://unsplash.com/',
               'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
           self.num = 1
           if '图片' not in os.listdir('.'):
               os.mkdir('图片')
           self.path = os.path.join(os.path.abspath('.'), '图片')
           os.chdir(self.path)  # 进入文件下载路径
    
       # 获取ajax返回的JSON中链接,并进行请求
       async def __get_content(self, link):
           async with aiohttp.ClientSession() as session:
               response = await session.get(link,headers=self.headers)
               content = await response.read()# 读取图片的二进制数据
               return content
    
       # 对ajax进行请求,返回JSON响应
       def __get_img_links(self, page):
           url = 'https://unsplash.com/napi/photos'
           data = {
               'page': page,
               'per_page': 12,
           }
           response = requests.get(url, headers=self.headers,params=data)
           if response.status_code == 200:
               return response.json()
           else:
               print(f'请求失败,状态码为{response.status_code}')
    
       # 下载图片
       # img:tuple元组
       # img[0]:图片的id
       # img[1]:图片的下载链接
       async def __download_img(self, img):
           # 调用__get_content()方法,返回图片的二进制数据
           content = await self.__get_content(img[1])
           with open(img[0]+'.jpg', 'wb') as f:
               f.write(content)
           print(f'下载第{self.num}张图片成功')
           self.num += 1
    
       # 调度函数,整合前面的函数
       def run(self):
           start = time.time()
           for x in range(1, 101):  # 下载一百页的图片就可以了,或者自己更改页数
               links = self.__get_img_links(x)
               tasks = [asyncio.ensure_future(self.__download_img((link['id'], link['links']['download']))) for link in links]
               loop = asyncio.get_event_loop()
               loop.run_until_complete(asyncio.wait(tasks))
               # 测试速度使用,如需要下载多张图片可以注释这段代码
               if self.num >= 10: 
                   break
           end = time.time()
           print(f'共运行了{end-start}秒')
    
    def main():
       spider = Spider()
       spider.run()
    
    if __name__ == '__main__':
       main()
    

    4. 结果展示


    写在最后:

    参考资料:

    python爬虫涉及的东西相对较多,需要不断地积累、总结,可以成为我们学习python的一个不错的方法。

    限于篇幅,代码无法一一细讲,还望各位大佬多包涵。

    人生苦短,重拾Python。
    Per Week,Hard Work!

    相关文章

      网友评论

          本文标题:异步 & ajax | 下载unplash高清大图

          本文链接:https://www.haomeiwen.com/subject/dznqnqtx.html