有时在使用requests抓取页面会遇到得到的结果与在浏览器 中看到的结果不一样,在浏览器检查元素中可以看到的正常的显示的网页数据,但是requests请求得到的结果却没有。这是因为requests请求得到的时原始的html文档,而浏览器中的界面确实经过JavaScript处理数据生成的结果,这些数据来源可能不同,有的时Ajax加载的,可能包含在html文档中,也有可能经过JavaScript渲染得到的。
对于Ajax(全称:Asynchronous JavaScript and XML),即异步的JavaScript和XML,是一种利用JavaScript技术在保证页面不刷新的情况下与服务器交换数据并更新部分网页的技术。
对于没有使用Ajax技术的网页来说,要想更新内容,就必须刷新整个页面,但使用Ajax就可以在后台完成与服务器的数据交互,获取到数据之后,再利用JavaScript改变网页即可。
这里以果壳网科学人为例,url为:“https://www.guokr.com/scientific/”,在文章下拉中我们并没有发现有翻页的操作,但会出现一个加载动画,然后下方又出现了新的内容,这个过程就是Ajax加载的过程,而网页的连接并没有改变。
Ajax加载动画

Ajax的分析:

Ajax具体又是如何实现这一过程的呢。从发送Ajax请求到网页更新过程中其实可以简单分为一下3个部分:
1)发送请求;
2)解析内容;
3)渲染网页
这个过程基本都需要以来JavaScript来实现,因为不是专业的,这里就不班门弄斧了,下面具体来说一下分析方法;
以chrome浏览器来介绍,打开链接:“https://www.guokr.com/scientific/”,打开开发者工具,并切换到network选项卡,如下图所示:
network面板结果
这里可以看到非常多的条目,但Ajax的请求是一种特殊的类型,叫做xhr,在选项栏直接选区XHR,则剩下显示的就都是Ajax请求了,并且随着下滑在下方会不断的出现新的Ajax请求,下面就可以通过分析这个请求去实现数据的爬取了。(在请求头信息中发现X-Requested-With: XMLHttpRequest字段即为Ajax请求)
选定其中一个请求,进入详情界面,如下图:
可以发现这是一个GET类型的请求,请求的链接为:’https://www.guokr.com/apis/minisite/article.json?retrieve_type=by_subject&limit=20&offset=38&_=1545367819629‘,请求的参数有3个:retrieve_type,limit和offset,通过查看其他请求发现retrieve_type,limit始终如一,改变的只有offset值,即控制分页的参数,且规律很简单,第一页为18,此后每一页增加20.
接下来观察这个请求的响应内容,即preview界面,如下图:
响应内容
可以发现这个响应内容是JSON格式的,浏览器帮我们做了解析,可以看到信息就是在result里面,这里我们只需要得到文章的链接即可,即url字段,然后在每一个详情页面对文章内容解析。
接下来是具体代码的实现:
首先定义一个方法来获取每次请求的结果,在请求时,将offset作为参数传入来构造url,代码如下:

import requests
from urllib.parse import urlencode
def get_index(offset):base_url = 'http://www.guokr.com/apis/minisite/article.json?'data = {'retrieve_type': "by_subject",'limit': "20",'offset': offset}url = base_url + urlencode(data)#print(url)try:headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'}resp = requests.get(url,headers=headers)if codes.ok == resp.status_code:return resp.json()except requests.ConnectionError:return None

定义了base_url来实现url前半部分,构造data字典,使用urlencode()方法将参数转换为GET请求参数,实现url的拼接,使用requests的get()方法请求链接,判断状态码为200后,返回json格式的结果。
下面定义一个方法去解析出每篇文章对应的链接:

import json
def get_url(json):if json.get('result'):result = json.get('result')for item in result:yield item.get('url')

在返回的内容中得到result,然后遍历它得到文章的url。
通过得到的文章链接欸,然后就可以在新页面解析得到文章具体内容,这里我们获取文章标题,作者以及正文,代码如下:

from bs4 import BeautifulSoup as bsp
def get_text(url):html=requests.get(url).textprint(html)soup=bsp(html,'lxml')title=soup.find('h1',id='articleTitle').get_text()autor=soup.find('div',class_="content-th-info").find('a').get_text()article_content=soup.find('div',class_="document").find_all('p')all_p = [i.get_text() for i in article_content if not i.find('img') and not i.find('a')]#去除标签article = '\n'.join(all_p)yield {"title":title,"autor":autor,"article":article}

这里使用BeautifulSoup来解析html,返回了title,autor以及article字段,其中去除标签的方法可以借用pyquery库的text()方法来实现。

最后时文章的保存,我们选择保存为txt文本格式,每一篇文章为一个文件,以获取的title字段命名即可,代码如下:

def save_article(content):try:if content.get('title'):filename=str(content.get('title'))+'.txt'with open(file_name, 'w',encoding='utf-8') as f:#f.write(json.dumps(content,ensure_ascii=False))f.write('\n'.join([str(content.get('title')),str(content.get('autor')),str(content.get('article'))]))print('Downloaded article path is %s' % filename)else:print('Already Downloaded', file_path)except requests.ConnectionError:print('Failed to Save Image,item %s' % content)

这样就实现了获取文章的保存,效果如下图:

当然我们也可以将其保存到mongodb数据库中,代码如下:

from pymongo import MongoClient
client=MongoClient()
db=client['guoke']
collection=db['guoke']
def save_to_mongo(content):if collection.insert(dict(content)):print('saved to mongo' %content.get('title'))

最后通过传入offset来实现翻页爬取,代码如下:

import time
def main(offset):result=get_index(offset)all_url=get_url(result)for url in all_url:article=get_text(url)for art in article:#print(art)save_article(art)GROUP_START = 0
GROUP_END = 10if __name__ == '__main__':for i in range(GROUP_START,GROUP_END+1):main(offset=i*20+18)time.sleep(1)

这样虽然也可以实现功能,但因为还是一个进程,会导致速度很慢,这里我们选择使用进程池的方法,将代码可以修改为:

GROUP_START = 0
GROUP_END = 10
from multiprocessing.pool import Pool
if __name__ == '__main__':pool=Pool()pool.map(main,[x*20+18 for x in range(GROUP_START,GROUP_END+1)])time.sleep(1)

这里通过GROUP_START,GROUP_END两个参数来控制爬取的页数.因为没有使用代理,这里加入一个休眠时间防止请求过于频繁。
这样就实现了Ajax加载页面的数据爬取,初步做到了可见即可爬的设想。
ps:github地址如下:‘https://github.com/linl12138/Ajax_guoke’

python爬虫学习笔记分析Ajax爬取果壳网文章相关推荐

  1. Python爬虫学习(六)爬取mzitu网图片

    效果: 分析 通过requests.get()发出GET请求,通过response.text接收html页面,通过xpath获取我们需要的a标签, 再次通过requests.get()访问这个图片链接 ...

  2. 分析ajax爬取果壳网

    一.确定要爬取的网页 首先选择要爬取的网页,我要爬取的是果壳网,url为:https://www.guokr.com/scientific/ 爬取每篇文章的标题.名字.作者.发布时间等信息 二.分析网 ...

  3. [Python3网络爬虫开发实战] --分析Ajax爬取今日头条街拍美图

    [Python3网络爬虫开发实战] --分析Ajax爬取今日头条街拍美图 学习笔记--爬取今日头条街拍美图 准备工作 抓取分析 实战演练 学习笔记–爬取今日头条街拍美图 尝试通过分析Ajax请求来抓取 ...

  4. 从入门到入土:Python爬虫学习|实例练手|爬取百度翻译|Selenium出击|绕过反爬机制|

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  5. 从入门到入土:Python爬虫学习|实例练手|爬取猫眼榜单|Xpath定位标签爬取|代码

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  6. 从入门到入土:Python爬虫学习|实例练手|爬取新浪新闻搜索指定内容|Xpath定位标签爬取|代码注释详解

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  7. 从入门到入土:Python爬虫学习|实例练手|爬取百度产品列表|Xpath定位标签爬取|代码注释详解

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  8. 从入门到入土:Python爬虫学习|实例练手|爬取LOL全英雄信息及技能||异步加载|初级难度反扒处理|寻找消失的API

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  9. [python爬虫] BeautifulSoup和Selenium简单爬取知网信息测试

    作者最近在研究复杂网络和知识图谱内容,准备爬取知网论文相关信息进行分析,包括标题.摘要.出版社.年份.下载数和被引用数.作者信息等.但是在爬取知网论文时,遇到问题如下:   1.爬取内容总为空,其原因 ...

最新文章

  1. NGUI创建Camera参数为Simple 2D的UI UI对象的结构UI Root(2D)
  2. android快速打包工具下载,【Android】多渠道打包,其实可以更快
  3. Centos调整时间时区
  4. Android开发之NDK下载与NDK更新
  5. error: [FabricCAClientService.js]: Failed to enroll admin, error:%o message=Calling enroll endpoint
  6. python/socket编程之粘包
  7. 【Flink】分布式快照算法—— Chandy-Lamport 算法
  8. 三门问题的MonteCarlo仿真方法
  9. C# 调用并执行SQL脚本文件
  10. 分享PHP获取客户端IP的几种不同方式
  11. 用python 代码写一个表白I love you
  12. android json解析歌词,网易云歌词获取
  13. 通达OA数据库服务断电无法启动的处理方法(亲测2020-10-07。通达OA2017版本)
  14. 寒假刷刷算法题(13)
  15. Vue todos代办事项功能
  16. html+JavaScript 实现贪吃蛇程序
  17. Scrum立会报告+燃尽图(Beta阶段第五次)
  18. Rewritecond介绍
  19. 会声会影2023最新版功能介绍及使用教程
  20. Cannot load configuration class: org.springframework.boot.autoconfigure报错 如何解决?注意核对版本

热门文章

  1. 【Unity】U3D TD游戏制作实例(三)相机管理器、生成敌人优化、敌人血槽小组件
  2. Matlab应变片仿真,应变片组的命名规则
  3. signature=e7a4f21fa0bd38abc7e1a2451a8b7b26,Win10 14328起“迅雷7.9、迅雷极速版”崩溃修正补丁...
  4. 电源上的sense什么意思_开关电源基本术语
  5. 【转载】androidstudo如何跨越这个厚厚的墙,亲测有效 Could not resolve com.android.tools.build:gradle:
  6. python3之Scrapy+Selenium切换iframe抓取网易云音乐排行榜
  7. resize用法matlab,opencv的resize和matlab的imresize函数的计算
  8. 音视频OSD——制作ASCII点阵字模并叠加到YUV图像中
  9. 编程番外篇:Rider体验与常用功能分享
  10. 以太坊柏林升级前的紧急刹车