当前位置:首页 » 《随便一记》 » 正文

动态加载内容爬取,Ajax爬取典例

23 人参与  2022年07月25日 12:16  分类 : 《随便一记》  评论

点击全文阅读


本问包含内容,Ajax数据获取,线程池简单使用,xlwt模板数据写入exel

有时候我们在用 requests 抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据,但是使用 requests 得到的结果并没有。这是因为 requests 获取的都是原始的 HTML 文档,而浏览器中的页面则是经过 JavaScript 处理数据后生成的结果,这些数据的来源有多种,可能是通过 Ajax 加载的,可能是包含在 HTML 文档中的,也可能是经过 JavaScript 和特定算法计算后生成的。

目录

1.导入模块

2.获取请求头

3.获取Ajax加载数据

4.解析页面信息

5.将获取到的数据写入exel

6.开辟线程池运行程序

7.相对完整代码


下面我们以新发地为例获取Ajax动态加载的内容

1.导入模块

注意看代码注释

import requestsimport xlwt    # 用于将数据储存到exel文件from concurrent.futures import ThreadPoolExecutor  # 导入线程池给爬虫加速

简单请求我们使用requests就好 

2.获取请求头

在开发者面板找到如下请求头,这是Ajax数据获取所需的请求头

如果想要运行注意根据实际情况修改请求头参数

base_url = "http://xinfadi.com.cn/getPriceData.html"headers = {    'Host': 'xinfadi.com.cn',     # 在开发者面板都可以找到的请求头    'Origin': 'http://xinfadi.com.cn',    'Referer': 'http://xinfadi.com.cn/priceDetail.html',    'User-Agent': '',  # 填写自己的User-Agent    'X-Requested-With': 'XMLHttpRequest'   # 获取Ajax数据需要加入的请求}

链接可以根据实际情况填入

3.获取Ajax加载数据

# 爬取页面原码(Ajax)def get_page(url, headers, current):    print(f"正在爬取第{current}页")    # post请求需要的参数在Payload可找到    params = {            'limit': 20,   # 页面最多显示数据的条数,10或20            'current': current,  # 页数,第几页            'pubDateStartTime': '',            'pubDateEndTime': '',            'prodPcatid': '',            'prodCatid': '',            'prodName': ''        }    response = requests.post(url, data=params, headers=headers)  # 根据网页提示使用post请求    json_source = response.json()["list"]   # 将Ajax数据转化为json格式后提取list条目的内容    page_parse(json_source, all_info)  # 调用page_parse提取数据

4.解析页面信息

将获取到的信息都保存到字典当中

如果想要运行注意根据实际get_page函数返回的json数据给字典的键(key)赋值

如一级分类是否对应prodCat

# 提取数据def page_parse(json_source, all_info):    # all_info为列表,包含每件产品的信息    for item in json_source:    # type(item)为字典        all_info["一级分类"].append(item.get("prodCat"))   # value对应的每个列表包含有所有产品的数据        all_info["二级分类"].append(item.get("prodPcat"))        all_info["产品名"].append(item.get("prodName"))        all_info["最高价"].append(item.get("highPrice"))        all_info["最低价"].append(item.get("lowPrice"))        all_info["平均价"].append(item.get("avgPrice"))        all_info["规格"].append(item.get("specInfo"))        all_info["产地"].append(item.get("place"))        all_info["单位"].append(item.get("unitInfo"))        all_info["发布日期"].append(item.get("pubDate"))

5.将获取到的数据写入exel

这里细节比较多,不熟悉xlwt模块的可以跳过

# 保存数据def save_data_exel(all_info):    book = xlwt.Workbook(encoding="utf-8")   # 打开新工作薄    sheet = book.add_sheet('新发地', cell_overwrite_ok=True)  # cell_overwrite_ok=Tru时重复写入单元格不会报错    col = list(all_info.keys())   # col获取all_info的键将作为标题头写入exel    value = list(all_info.values())   # value则是作为产品内容写入exel    for i in range(10):           # 标题头写入操作        sheet.write(0, i, col[i])    # 根据all_info的格式特点采取按列储存数据    for j in range(10):   # 列        for k in range(20*(MAX_PAGE-1)):  # 行。MAX_PAGE无法取0,因为current从1开始,故MAX_PAGE-1            sheet.write(k+1, j, value[j][k])  # 为了不覆盖第一行的标题行从第1行写入,而不是第0行    book.save('新发地商品信息.xls')   # 文件名+保存Exel文件

6.开辟线程池运行程序

简单的线程池使用

if __name__ == '__main__':    base_url = "http://xinfadi.com.cn/getPriceData.html"    headers = {        'Host': 'xinfadi.com.cn',     # 在开发者面板都可以找到的请求头        'Origin': 'http://xinfadi.com.cn',        'Referer': 'http://xinfadi.com.cn/priceDetail.html',        'User-Agent': '',  # 填写自己的User-Agent        'X-Requested-With': 'XMLHttpRequest'   # 获取Ajax数据需要加入的请求    }    all_info = {        # all_info包含获取到的所有产品数据        "一级分类": [],        "二级分类": [],        "产品名": [],        "最高价": [],        "最低价": [],        "平均价": [],        "规格": [],        "产地": [],        "单位": [],        "发布日期": []    }    with ThreadPoolExecutor(50) as T:    # 创建包含50个线程的线程池        for i in range(1, MAX_PAGE):   # post的current参数从1开始不能取0            # 不能写成T.submit(get_page, base_url=base_url, headers=headers, current=i)不然获取不到数据            T.submit(get_page, base_url, headers, i)  # 将函数调用的任务交给线程池来做    save_data_exel(all_info)    print("数据储存完成")

7.相对完整代码

为什么是相对完整呢?里面User-Agent还需要自行填入

import requestsimport xlwt    # 用于将数据储存到exel文件from concurrent.futures import ThreadPoolExecutor  # 导入线程池给爬虫加速MAX_PAGE = 200  # 爬取最大页数>=1,因为range(1,1)为None# 爬取页面原码(Ajax)def get_page(url, headers, current):    print(f"正在爬取第{current}页")    # post请求需要的参数在Payload可找到    params = {            'limit': 20,   # 页面最多显示数据的条数,10或20            'current': current,  # 页数,第几页            'pubDateStartTime': '',            'pubDateEndTime': '',            'prodPcatid': '',            'prodCatid': '',            'prodName': ''        }    response = requests.post(url, data=params, headers=headers)  # 根据网页提示使用post请求    json_source = response.json()["list"]   # 将Ajax数据转化为json格式后提取list条目的内容    page_parse(json_source, all_info)  # 调用page_parse提取数据# 提取数据def page_parse(json_source, all_info):    # all_info为列表,包含每件产品的信息    for item in json_source:    # type(item)为字典        all_info["一级分类"].append(item.get("prodCat"))    # value对应的每个列表包含有所有产品的数据        all_info["二级分类"].append(item.get("prodPcat"))        all_info["产品名"].append(item.get("prodName"))        all_info["最高价"].append(item.get("highPrice"))        all_info["最低价"].append(item.get("lowPrice"))        all_info["平均价"].append(item.get("avgPrice"))        all_info["规格"].append(item.get("specInfo"))        all_info["产地"].append(item.get("place"))        all_info["单位"].append(item.get("unitInfo"))        all_info["发布日期"].append(item.get("pubDate"))# 保存数据def save_data_exel(all_info):    book = xlwt.Workbook(encoding="utf-8")   # 打开新工作薄    sheet = book.add_sheet('新发地', cell_overwrite_ok=True)  # cell_overwrite_ok=Tru时重复写入单元格不会报错    col = list(all_info.keys())   # col获取all_info的键将作为标题头写入exel    value = list(all_info.values())   # value则是作为产品内容写入exel    for i in range(10):           # 标题头写入操作        sheet.write(0, i, col[i])    # 根据all_info的格式特点采取按列储存数据    for j in range(10):   # 列        for k in range(20*(MAX_PAGE-1)):  # 行。MAX_PAGE无法取0,因为current从1开始,故MAX_PAGE-1            sheet.write(k+1, j, value[j][k])  # 为了不覆盖第一行的标题行从第1行写入,而不是第0行    book.save('新发地商品信息.xls')   # 文件名+保存Exel文件if __name__ == '__main__':    base_url = "http://xinfadi.com.cn/getPriceData.html"    headers = {        'Host': 'xinfadi.com.cn',     # 在开发者面板都可以找到的请求头        'Origin': 'http://xinfadi.com.cn',        'Referer': 'http://xinfadi.com.cn/priceDetail.html',        'User-Agent': '',  # 填写自己的User-Agent        'X-Requested-With': 'XMLHttpRequest'   # 获取Ajax数据需要加入的请求    }    all_info = {        # all_info包含获取到的所有产品数据        "一级分类": [],  # value对应的每个列表包含有所有产品的数据        "二级分类": [],        "产品名": [],        "最高价": [],        "最低价": [],        "平均价": [],        "规格": [],        "产地": [],        "单位": [],        "发布日期": []    }    with ThreadPoolExecutor(50) as T:    # 创建包含50个线程的线程池        for i in range(1, MAX_PAGE):   # post的current参数从1开始不能取0            # 不能写成T.submit(get_page, base_url=base_url, headers=headers, current=i)不然获取不到数据            T.submit(get_page, base_url, headers, i)  # 将函数调用的任务交给线程池来做    save_data_exel(all_info)    print("数据储存完成")

下期见


点击全文阅读


本文链接:http://zhangshiyu.com/post/43782.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1