第6章 Ajax数据爬取

有些网页可以正常看到,但requests得到的页面却不一样。因为requests得到原始html文档,然而有些内容(比如Ajax)通过浏览器展示的是经过JavaScript处理数据后生成的结果。数据来源无非有下面几种:Ajax加载、包含在html文档内、经过JavaScript渲染。requests获得的就是包含在html文档内的,倘若遇到页面内容是经过JavaScript处理的结果呢?那么就需要引入Ajax。

数据加载时一种异步加载方式,原始页面最初不会包含某些数据,原始页面加载完后,通过用户的操作,会再向服务器请求某个接口获取数据,然后数据才被处理从而展示到网页上,这个过程就是发送了一个Ajax请求。

Ajax---异步的JavaScript和XML,利用JavaScript在保证页面不被刷新、页面链接不改变情况下与服务器交换数据并更新部分网页的技术。发送Ajax请求到网页更新的过程:1、发送请求;2、解析内容;3、渲染网页

1、发送请求

Ajax也是由JavaScript实现的,执行了如下过程:

  1. 新建XMLHttpRequest对象
  2. 调用onreadystatechange属性设置监听
  3. 然后调用open()和send()方法向某个链接(通常是服务器)发送请求
  4. 一旦监听到服务器返回响应时,onreadystatechange对应的方法被触发,该方法内解析响应内容

2、解析内容

得到响应,相应方法被触发,可利用xmlhttp的responseText属性得到响应的内容。

返回的内容或HTML、JSON,需要在方法JavaScript进一步处理

3、渲染网页

调用JavaScript来根据内容对网页进行修改。比如,通过document.getElementById().innerHTML可以对某个元素内的源代码进行更改,网页内容随之改变,也称为DOM操作。

二、Ajax分析方法

1、查看请求

开发者工具,Elements中观察网页源码,Network中记录页面加载过程中浏览器与服务器之间发送请求和接受响应的所有记录

Ajax请求类型为xhr,通过上方选择XHR,只观察Ajax请求信息,单击network中某一次记录发现,

点击一次Ajax请求信息,右侧栏内发现,Headers中,最下面的一个信息,就标记了此请求为Ajax请求。

Response Headers中发现响应内容为JSON格式等信息,得到该响应内容为Ajax请求的结果。

Preview中是具体的响应内容。

Response是输入搜索的真实结果,preview是将真实的结果通过json格式化,显示出来。

故此,网页显示是通过Ajax请求,从后台拿到数据后进一步渲染出来的。

下面以微博为例子:

import os
import requests
from urllib.parse import urlencode
import json
import csv

from pyquery import PyQuery as pq
base_url = 'https://m.weibo.cn/api/container/getIndex?'
headers = {
    'Host': 'm.weibo.cn',
    'Referer': "https://m.weibo.cn/u/2803301701",
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',# 标识为Ajax请求
}

max_page=1

def get_page(page):
    params={
        'uid': '2803301701',# 唯一性
        'type': '人民日报',# 可通过
        'containerid': '1076032803301701',
        # 注意此处containerid与博主首页链接处的不同
        'page': page
    }
    url = base_url+urlencode(params)
    try:
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.json()
    except requests.ConnectionError as e:
        print('Error', e.args)


def parse_page(json):
    # print(json)
    items=json.get('data').get('cards')
    for item in items:
        item=item.get('mblog')
        weibo={}
        weibo['时间'] = item.get('created_at')#时间
        weibo['正文'] = pq(item.get('text')).text() #正文
        weibo['点赞'] = item.get('attitudes_count')#点赞
        weibo['评论'] = item.get('comments_count')#评论
        weibo['转发'] = item.get('reposts_count')#转发

        yield weibo

def get_initial_Info():
    params = {
        'uid': '2803301701',  # 唯一性
        'type': '人民日报',  # 可通过
        'containerid': '1005052803301701',
        # 这里和微博内容处不一样,此处id为用户个人信息的标识
        'value': '2803301701'
        # 微博博文页面链接没有value,但个人信息标识连接处须有此value标识
    }
    url = base_url + urlencode(params)
    try:
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            json=response.json()
    except requests.ConnectionError as e:
        print('Error', e.args)

    json=json.get('data').get('userInfo')
    # print(json)
    # .data.userInfo.statuses_count
    max_page = int(int(json.get('statuses_count')) / 9)
    print(max_page)
    user_Info = {}
    user_Info['博主'] = json.get('screen_name')
    user_Info['关注'] = json.get('follow_count')
    user_Info['粉丝'] = json.get('followers_count')
    user_Info['介绍'] = json.get('description')
    user_Info['博文数量'] = json.get('statuses_count')
    return user_Info

def save_file(items):
    with open('weibo.csv','w',encoding='utf-8') as csvfile:
        # 追加形式写入:a,并规定写入的指定编码
        fieldnames=['时间','正文','点赞','评论','转发']
        # 要注意fieldnames与传入数据的字典类型要一致,否则就会出错
        #字典类型的写入
        writer = csv.DictWriter(csvfile,fieldnames=fieldnames)
        writer.writeheader()

        for item in items:
            print(item)
            writer.writerow(item)

if __name__=='__main__':
    # 先访问一次用户页面,获取微博数量,确定要爬取的页面数
    user_Info=get_initial_Info()
    print(user_Info)
    for page in range(1,max_page+1):
        json=get_page(page)
        results=parse_page(json)
        # for result in results:
        #     print(result)
        save_file(results)

代码未完成,后续还要完善,学一点,完善一些。

发布了92 篇原创文章 · 获赞 23 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Pit3369/article/details/86632763