Ajax是利用 JavaScript在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。

Ajax基本原理

  1. 发送请求
  2. 解析内容
  3. 渲染页面

查看请求

Python 网络爬虫之 Ajax 数据爬取

Ajax结果提取

爬取一个人微博的前面10页

分析过程

Python 网络爬虫之 Ajax 数据爬取Python 网络爬虫之 Ajax 数据爬取

Python 网络爬虫之 Ajax 数据爬取Python 网络爬虫之 Ajax 数据爬取

Python代码实现

from urllib.parse import urlencode
import requests

# 对https://m.weibo.cn/u/2830678474网页审查分析
base_url = 'https://m.weibo.cn/api/container/getIndex?'
headers = {
    'Host': 'm.weibo.cn',
    'Referer': 'https://m.weibo.cn/u/2830678474',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/75.0.3770.100 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest'
}


# page 为页码,返回每一页响应的JSON编码内容(如果有)
def get_page(page):
    params = {
        'type': 'uid',
        'value': '2830678474',
        'containerid': '1076032830678474',
        'page': page
    }
    url = base_url + urlencode(params)
    try:
        response = requests.get(url, headers=headers)
        if response.status_code == 200:             # response.status_code获取网页状态码
            return response.json()                  # response.json()返回响应的JSON编码内容
    except requests.ConnectionError as e:           # 出现异常,捕获并输出其异常信息
        print('Error:', e.args)


from pyquery import PyQuery


# 根据获取的json编码,筛选出我们需要的内容
def parse_page(json):
    if json:
        items = json.get('data').get('cards')           # 获取json编码中的data里面的cards的内容,返回结果是一个迭代器
        for item in items:                              # 遍历每条cards内容
            item = item.get('mblog')                    # 获取mblog中的内容
            weibo = {}
            weibo['id'] = item.get('id')                            # 获取'id'内容
            weibo['text'] = PyQuery(item.get('text')).text()
            # 利用get()获取'text'内容,再利用PyQuery()方法初始化Json编码形式,再利用text()获取子节点的文本表示形式。
            weibo['attitudes'] = item.get('attitudes_count')            # 获取'赞'的个数
            weibo['comments'] = item.get('comments_count')              # 获取'评论'数
            weibo['reposts'] = item.get('reposts_count')                # 获取'分享'次数
            yield weibo


from pymongo import MongoClient

client = MongoClient()          # 连接MongoDB
db = client['weibo']            # 指定weibi数据库
collection = db['weibo']        # 指定weibo集合


# 将数据插入Mongo数据库
def save_to_mongo(result):
    if result:
        collection.insert_one(result)                               # 调用insert_one()方法,将一条数据插入到数据库中
        print('Saved to Mongo')


if __name__ == '__main__':
    for page in range(1, 11):               # 获取10页
        json = get_page(page)
        results = parse_page(json)
        for result in results:
            print(result)
            save_to_mongo(result)

结果

  1. 部分输出

    {'id': '4393921821587600', 'text': '老婆我爱你! 花絮慎点啊。', 'attitudes': 16, 'comments': 4, 'reposts': 1}
    Saved to Mongo
    {'id': '4393850371867195', 'text': '执行力非常重要,做一个实干者。', 'attitudes': 1, 'comments': 0, 'reposts': 3}
    Saved to Mongo
    {'id': '4393608914828988', 'text': '欧耶!!!!!@长泽牙妹\n济南', 'attitudes': 9, 'comments': 15, 'reposts': 0}
    Saved to Mongo
    {'id': '4393563145925473', 'text': '叔叔要和我喝酒了。\n我好慌。 济南', 'attitudes': 10, 'comments': 20, 'reposts': 0}
    Saved to Mongo
    
  2. MongoDB数据库查看数据

    Python 网络爬虫之 Ajax 数据爬取

异步(Ajax)爬取今日头条街拍美图

类似上面爬微博的方法,爬取今日头条街拍美图

import requests
from urllib.parse import urlencode
base_url = 'https://www.toutiao.com/api/search/content/?'
headers = {
    'Host': 'www.toutiao.com',
    'Referer': 'https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/75.0.3770.100 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest'
}


# 一个关于offset和timestamp数据的列表
def offset_timestamp():
    offsets = [offset for offset in range(8)]
    timestamps = [1563094062541, 1563094066268, 1563094068231, 1563094069948, 1563094071549, 1563094073370,
                  1563094075154, 1563094077384]
    tuple_list = []
    for i in range(8):
        tuple_list.append(
            (offsets[i], timestamps[i])
        )
    return tuple_list


# 获取页面Json编码
def get_page(tuple_):
    params = {
        'aid': '24',
        'app_name': 'web_search',
        'offset': tuple_[0],
        'format': 'json',
        'keyword': '%E8%A1%97%E6%8B%8D',
        'autoload': 'true',
        'count': '20',
        'en_qc': '1',
        'cur_tab': '1',
        'from': 'search_tab',
        'pd': 'synthesis',
        'timestamp': tuple_[1]
    }
    url = base_url + urlencode(params)
    try:
        response = requests.get(url, headers)
        if response.status_code == 200:
            return response.json()
    except requests.ConnectionError as e:
        print('Error:', e.args)
        return None


# 获取图片URL
def get_images(json):
    if json.get('data'):
        data = json.get('data')
        if data.get('abstract'):
            for item in data.get('data'):
                abstract = item.get('abstract')
                images = item.get('image_list')
                for image in images:
                    yield {
                        'image': image.get('url'),
                        'abstract': abstract
                    }


import os
from hashlib import md5


# 保存图片
def save_image(item):
    if not os.path.exists(item.get('abstract')):                   # os.path.exists(path)方法,测试路径是否存在
        os.mkdir(item.get('abstract'))                          # os.mkdir()方法,创建一个目录
    try:
        response = requests.get(item.get('image'))              # 对获取的image_URL发送请求
        if response.status_code == 200:
            file_path = '{0}/{1}.{2}'.format(item.get('abstract'), md5(response.content).hexdigest(), 'jpg')
            # 图片的名称可以使用MD5值,这样可以去除重复。
            # response.content属性返回响应内容。
            # hexdigest()方法,以十六进制数字的字符串形式返回摘要值。
            if not os.path.exists(file_path):
                with open(file_path, 'wb') as f:
                    f.write(response.content)       # 将响应的内容以二进制的形式写入文件file_path中
            else:
                print('Already Downloaded', file_path)
    except requests.ConnectionError as e:
        print(
            'Error:', e.args,
            '\nFailed to Save Image'
        )


if __name__ == '__main__':
    tuple_list = offset_timestamp()
    for tuple_ in tuple_list:
        json = get_page(tuple_)
        for item in get_images(json):
            print(item)
            save_image(item)

相关文章: