Python 网络爬虫之 Ajax 数据爬取

Ajax 概述

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

Ajax基本原理

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

查看请求

Ajax结果提取

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

分析过程

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数据库查看数据

异步(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)
posted @ 2019-07-15 11:38  LeeHua  阅读(2079)  评论(0编辑  收藏  举报