爬虫学习记录(五)————ajax动态爬取

GitHub地址:https://github.com/yunlong-G/learn/blob/master/spider_learn/ajax%E5%8A%A8%E6%80%81%E7%88%AC%E5%8F%96.ipynb

ajax爬取原理与解析

Ajax,全称为 Asynchronous JavaScript and XML,即异步的 JavaScript 和 XML。它不是一门编程语言,而是利用 JavaScript 在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。

传统的网页,如果你想更新其内容,那么必须要刷新整个页面。有了 Ajax,便可以在页面不被全部刷新的情况下更新其内容。在这个过程中,页面实际上在后台与服务器进行了数据交互,获取到数据之后,再利用 JavaScript 改变网页,这样网页内容就会更新了。

原理

初步了解了 Ajax 之后,我们再来详细了解它的基本原理。发送 Ajax 请求到网页更新的过程可以简单分为以下 3 步:

  • 发送请求
  • 解析内容
  • 渲染网页

下面我们分别详细介绍一下这几个过程

发送请求

一个静态的网站需要向服务器发送请求然后获得了html文件后渲染,ajax也需要向服务器发送请求,获得html或者json后进行渲染,发送请求的过程一般通过JavaScript进行。

var xmlhttp;
if (window.XMLHttpRequest) {
    
    
    //code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();} else {
    
    //code for IE6, IE5
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
    
    if (xmlhttp.readyState==4 && xmlhttp.status==200) {
    
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
}
xmlhttp.open("POST","/ajax/",true);
xmlhttp.send();

这是 JavaScript 对 Ajax 最底层的实现,这个过程实际上是新建了 XMLHttpRequest 对象,然后调用 onreadystatechange 属性设置监听,最后调用 open() 和 send() 方法向某个链接(也就是服务器)发送请求。

前面我们用 Python 实现请求发送之后,可以得到响应结果,但这里请求的发送由 JavaScript 来完成。由于设置了监听,所以当服务器返回响应时,onreadystatechange 对应的方法便会被触发,我们在这个方法里面解析响应内容即可。

解析内容

得到响应之后,onreadystatechange 属性对应的方法会被触发,此时利用 xmlhttp 的 responseText 属性便可取到响应内容。这类似于 Python 中利用 requests 向服务器发起请求,然后得到响应的过程。

返回的内容可能是 HTML,也可能是 JSON,接下来我们只需要在方法中用 JavaScript 进一步处理即可。比如,如果返回的内容是 JSON 的话,我们便可以对它进行解析和转化。

渲染网页

JavaScript 有改变网页内容的能力,解析完响应内容之后,就可以调用 JavaScript 针对解析完的内容对网页进行下一步处理。比如,通过 document.getElementById().innerHTML 这样的操作,对某个元素内的源代码进行更改,这样网页显示的内容就改变了,这种对 Document 网页文档进行如更改、删除等操作也被称作 DOM 操作。

上例中,document.getElementById(“myDiv”).innerHTML=xmlhttp.responseText这个操作便将 ID 为 myDiv 的节点内部的 HTML 代码更改为服务器返回的内容,这样 myDiv 元素内部便会呈现出服务器返回的新数据,网页的部分内容看上去就更新了。

可以看到,发送请求、解析内容和渲染网页这 3 个步骤其实都是由 JavaScript 完成的。

我们再回想微博的下拉刷新,这其实是 JavaScript 向服务器发送了一个 Ajax 请求,然后获取新的微博数据,将其解析,并将其渲染在网页中的过程。

因此,真实的数据其实都是通过一次次 Ajax 请求得到的,如果想要抓取这些数据,我们需要知道这些请求到底是怎么发送的,发往哪里,发了哪些参数。如果我们知道了这些,不就可以用 Python 模拟这个发送操作,获取到其中的结果了吗?

Ajax 分析

在进行刷新页面时,网页本身的url并没有发生改变,如何找到ajax请求呢?我以崔老师学习的网站为例。

import requests
url = 'https://dynamic1.scrape.cuiqingcai.com/'
html = requests.get(url).text
print(html)
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>Scrape | Movie</title><link href=/css/chunk-700f70e1.1126d090.css rel=prefetch><link href=/css/chunk-d1db5eda.0ff76b36.css rel=prefetch><link href=/js/chunk-700f70e1.0548e2b4.js rel=prefetch><link href=/js/chunk-d1db5eda.b564504d.js rel=prefetch><link href=/css/app.ea9d802a.css rel=preload as=style><link href=/js/app.652ace7f.js rel=preload as=script><link href=/js/chunk-vendors.2540653d.js rel=preload as=script><link href=/css/app.ea9d802a.css rel=stylesheet></head><body><noscript><strong>We're sorry but portal doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.2540653d.js></script><script src=/js/app.652ace7f.js></script></body></html>

我们可以看到只有很少的html文件被返回,但是页面的内容很多不在html文件里。打开浏览器的检查模式,通过xhr可以看到请求,观察请求头文件,即可获得对应的url。在这里插入图片描述
通过xhr中看请求头文件获得对应的url,在这个网站里详情页和主界面页之前的url有一定规律,可以利用程序不断更新获取。

ajax爬取实例

# 引入需要的包
import requests
import logging
import json
from os import makedirs
from os.path import exists

RESULTS_DIR = 'results'
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s: %(message)s')
INDEX_URL = 'https://dynamic1.scrape.cuiqingcai.com/api/movie/?limit={limit}&offset={offset}'

# 爬取网站的基本信息
def scrape_api(url):
    logging.info('scraping %s...', url)
    try:
        response = requests.get(url)
        if response.status_code == 200:
            return response.json()
        logging.error('get invalid status code %s while scraping %s',response.status_code, url)
    except requests.RequestException:
        logging.error('error occurred while scraping %s', url, exc_info=True)

# 对每一个主界面获得url
LIMIT = 10
def scrape_index(page):
    url = INDEX_URL.format(limit = LIMIT, offset = LIMIT * (page - 1))
    return scrape_api(url)

# 对详情页的解析
DETAIL_URL = 'https://dynamic1.scrape.cuiqingcai.com/api/movie/{id}'
def scrape_detail(id):
    url = DETAIL_URL.format(id=id)
    return scrape_api(url)

# 存储数据
def save_data(data):
    name = data.get('name')
    data_path = f'{RESULTS_DIR}/{name}.json'
    json.dump(data, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent = 2)

# 链接调用
TOTAL_PAGE = 10
def main():
    for page in range(1, TOTAL_PAGE + 1):
        index_data = scrape_index(page)
        for item in index_data.get('results'):
            id = item.get('id')
            detail_data = scrape_detail(id)
            logging.info('detail data %s', detail_data)
            save_data(detail_data)
if __name__ == '__main__':
    main()

学习总结

我的理解,ajax就相当于一种持续连接,一次并不获得所有的对象,再需要的时候再次请求对象,进行解析渲染。而静态的网页一般就是直接获得所有的对象,然后渲染出来。相比之下,利用ajax可以使前后端分离,灵活性更高,但是爬取步骤繁琐。

おすすめ

転載: blog.csdn.net/yunlong_G/article/details/108443587