美文网首页
爬虫之异步加载(实战花瓣网)

爬虫之异步加载(实战花瓣网)

作者: 高金01 | 来源:发表于2018-09-29 11:07 被阅读0次

    本文章属于爬虫入门到精通系统教程第八讲

    本次我们会讲解两个知识点

    1. 异步加载
    2. headers中的Accept

    本次我们要抓取的是花瓣网美女照片美女花瓣,陪你做生活的设计师(发现、采集你喜欢的美女图片)花瓣网(http://huaban.com/favorite/beauty/

    本次我们会用到的辅助包

    scrapy/parsel (https://github.com/scrapy/parsel)(假如你用过scrapy,那么一定不陌生,这就是其中提取器)

    Parsel is a library to extract data from HTML and XML using XPath and CSS selectors
    简单来讲就是集成了xpath和css,只要你会xpath的话,那么用法没有什么区别

    >>> from parsel import Selector
    >>> sel = Selector(text=u"""<html>
    <body>
    <h1>Hello, Parsel!</h1>
    <ul>
    <li><a href="http://example.com">Link 1</a></li>
    <li><a href="http://scrapy.org">Link 2</a></li>
    </ul
    </body>
    </html>""")
    >>>
    >>> sel.css('h1::text').extract_first()
    u'Hello, Parsel!'
    >>>
    >>> sel.css('h1::text').re('\w+')
    [u'Hello', u'Parsel']
    >>>
    >>> for e in sel.css('ul > li'):
    print(e.xpath('.//a/@href').extract_first())
    http://example.com
    http://scrapy.org
    

    安装方法: pip install parsel

    scrapinghub/js2xml(https://github.com/scrapinghub/js2xml

    Convert Javascript code to an XML document
    简单来讲就是 将JavaScript代码转换为xml文档。然后可以使用xpath从JavaScript中提取数据,不用写一堆正则了。

    >>> import js2xml
    >>>
    >>> jscode = """function factorial(n) {
    ... if (n === 0) {
    ... return 1;
    ... }
    ... return n * factorial(n - 1);
    ... }"""
    >>> parsed = js2xml.parse(jscode)
    >>>
    >>> parsed.xpath("//funcdecl/@name") # extracts function name
    ['factorial']
    >>>
    >>> print js2xml.pretty_print(parsed) # pretty-print generated XML
    <program>
      <funcdecl name="factorial">
        <parameters>
          <identifier name="n"/>
        </parameters>
        <body>
          <if>
            <predicate>
              <binaryoperation operation="===">
                <left>
                  <identifier name="n"/>
                </left>
                <right>
                  <number value="0"/>
                </right>
              </binaryoperation>
            </predicate>
            <then>
              <block>
                <return>
                  <number value="1"/>
                </return>
              </block>
            </then>
          </if>
          <return>
            <binaryoperation operation="*">
              <left>
                <identifier name="n"/>
              </left>
              <right>
                <functioncall>
                  <function>
                    <identifier name="factorial"/>
                  </function>
                  <arguments>
                    <binaryoperation operation="-">
                      <left>
                        <identifier name="n"/>
                      </left>
                      <right>
                        <number value="1"/>
                      </right>
                    </binaryoperation>
                  </arguments>
                </functioncall>
              </right>
            </binaryoperation>
          </return>
        </body>
      </funcdecl>
    </program>
    

    安装方法: pip install js2xml

    开始爬虫

    我们先打开美女花瓣,陪你做生活的设计师(发现、采集你喜欢的美女图片)花瓣网(http://huaban.com/favorite/beauty/

    页面分析

    如果我们想把这里面所有美女照片抓取下来的话,那么我们的操作步骤应该是这样的

    1.打开首页的每一个”相框”,然后点进去

    image

    2.获取所有图片的链接,然后下载下来

    image

    程序实现:

    用程序实现的话,也是挺简单的

    1. 获取首页所有“相框”的链接
    2. 点进去每个链接
    3. 获取详情页的所有图片地址
    4. 下载图片

    代码:

    1. 获取首页所有“相框”的链接

    2. 我们打开美女花瓣,陪你做生活的设计师(发现、采集你喜欢的美女图片)花瓣网(http://huaban.com/favorite/beauty/

    3. 按F12

    4. 点击如图所示的位置

    5. image
    6. 点击任何一个相框,然后你会看到网页的源代码自动会跳到你当前选中的地方

    7. image
    8. 然后你就可以在这附近找找你想要的链接地址(可以看到/pins/1062650100/,我们可以打开这个地址看看,确认下是我们想要找的)

    9. image
    10. 可以看到图片是一样的,说明我们要找的没错

    11. image
    12. 那么既然我们找到了需要的链接,接下来就是用程序定位到这了。

    13. 可以看到链接这边有个class=”img x layer-view loaded”,那么我们可以用以下xpath来获取地址了
      //a[@class=”img x layer-view loaded”]/@href

    14. image

    用代码实现:

    import requests
    from parsel import Selector
    url = ‘http://huaban.com/favorite/beauty/‘
    headers = {‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36’}
    z = requests.get(url,headers=headers)
    print z.status_code
    #返回200
    #使用parsel中的Selector 来解析
    sel = Selector(text=z.text)
    print sel.xpath(‘//a[@class=”img x layer-view loaded”]/@href’)
    #发现返回为空
    

    这边为什么会返回空呢?不是应该返回所有链接的么?

    我们可以查看下网页源代码,可以发现的内容都是通过js渲染上去的,所以我们才获取不到内容(这个可以用js2xml来解析,先放在这里,到详情页再来处理。)

    image
    image

    所谓的异步加载

    1. 我们还是打开美女花瓣,陪你做生活的设计师(发现、采集你喜欢的美女图片)花瓣网(http://huaban.com/favorite/beauty/

    2. 可以发现我们把页面拖动到最下面,会自动加载出新的内容(整个页面没有跳转,这就是所谓的异步加载。有些网页是需要手动点击“加载更多的”,原理都是一样的)

    3. 获取异步加载的请求

    4. 打开F12

    5. 拖动到页面最下面(有些网站是点击加载更多)

    6. 注意 我有勾选”xhr”

    7. 可以看到每次页面到最底部,都会发送一个请求。这个请求就是所谓的异步加载请求。

    8. ! image
    9. 可以看到请求的参数如下:

    j0ga0has:

    max:1062527343

    limit:20

    wfl:1

    1. j0ga0has第一个参数不知道是怎么回事,先放着
    2. max是 最上面的pin_id
    3. limit 是每次返回的条数
    4. 有人可能会问,你怎么知道这个参数是干嘛的?其实都是试出来的(或者说看出来的)
    5. 如下图的pin_id,可以发现下一条请求的max就是上一条请求获取到的最后一个pin_id
    6. image
    7. 我们查看返回值,发现竟然是json格式的,这样的话,都不需要我们解析了,那我们找找我们需要的链接地址在哪。
    8. image
    9. 发现链接地址就是由pin_id拼接而成的,所以我们只要获取到这个pin_id就行。
    10. image

    用程序来实现:

    url = ‘http://huaban.com/favorite/beauty/‘
    params = { ‘j0ga0hbi’:’’, ‘max’:’1062161596’, ‘limit’:’100’, ‘wfl’:’1’}
    z1 = requests.get(url=url,params=params,headers=headers)
    print z1.status_code
    #返回200
    print z1.json()
    #报错
    
    image

    然后发现竟然报错了。。。

    为什么呢?我们查看请求的时候就是jsno格式的啊

    我们打印下源代码看看

    image

    你会看到竟然是<!DOCTYPE html><html这样的,但是我们上面查看请求的时候,明明是如下图这样的啊

    image

    那么到底是哪里出了问题呢?

    我们再次查看之前我们看到的异步请求

    可以发现它有几个 特别的请求头

    指定了格式为json ,那么我们加上去看看呢

    Accept:application/json
    X-Request:JSON
    X-Requested-With:XMLHttpRequest
    
    image
    headers1 = { ‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36’, ‘Accept’:’application/json’, ‘X-Request’:’JSON’, ‘X-Requested-With’:’XMLHttpRequest’ }
    z2 = requests.get(url=url,params=params,headers=headers1)
    print z2.content
    
    image

    可以看到返回值和我们之前一样了。

    获取pin_id

    image

    最后只要把pin_id拼接成url就可以了,如果你想要爬取所有的图片的话,那么你只需要把最后的pin_id 传入给max,再请求一次,直到pins为空为止

    在上面我们已经获取到了所有的详情页的地址,那么我们现在只要获取到图片链接就行

    1. 随便打开一个详情页花瓣(http://huaban.com/pins/1062650100/
    2. 查看图片地址
    3. image
    4. 复制图片地址到网页源代码里面找找看
    5. 全部复制,发现没有找到
    6. image
    7. 那么我们复制一部分
    8. 可以看到已经找到了,这边你也可以用正则表达式,来匹配所有的地址,但是太麻烦了,我们可以用js2xml
    9. image

    看代码.

    image
    image
    image

    就这样,我们已经把图片地址获取到了,只需要拼接下即可(记得去下重)

    最后再次总结一下

    看完本篇文章后,你应该要

    • 能知道如何抓取异步加载的请求
    • 了解js2xml的用法
    • 了解headers的用法

    最后代码都在 kimg1234/pachong(https://github.com/kimg1234/pachong/blob/master/huaban%E7%88%AC%E8%99%AB.ipynb

    填一个坑,我在http://mp.weixin.qq.com/s?__biz=MzU2OTAxNTcwMw==&mid=100000023&idx=1&sn=0c0ff48e9bfca19dca6c4ed5bad46e0a&chksm=7c846def4bf3e4f9bde83bc8aa966419022c86dea5db9a00918f3b0220f9432c38f3b991d44a#rd
    留下以下问题

    image

    其实解决方法也挺简单的,就是把content-type这一行注释掉。

    那么为什么注释掉就可以了呢?请仔细研究研究http协议。。。

    image

    相关文章

      网友评论

          本文标题:爬虫之异步加载(实战花瓣网)

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