大师兄的Python学习笔记(二十二): 爬虫(三)
大师兄的Python学习笔记(二十四): 爬虫(五)
五、爬取Ajax数据
- 为了实现前后端分离,越来越多的网站使用Ajax制作动态页面。
- 在这种情况下,原始页面获取不到有效数据,需要模拟Ajax请求获取数据。
1. 关于Ajax
- Ajax即异步的JavaScript和XML(Asynchronous JavaScript and XML), 是一种创建交互式网页应用的网页开发技术。
- Ajax利用JS实现在页面不刷新,链接不改变的情况下与服务器交换数据并更新部分网页的能力。
- 前台:HTML + JS + AJAX
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>sample</title>
<script type="text/javascript">
var xmlHttp;
function createXmlHttpRequest()
{
//创建XMLHttpRequest对象的方法
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = readyStateChangeHandle;
xmlHttp.open("GET","helloworld.xml",true);
xmlHttp.send(null);
}
function readyStateChangeHandle()
{ //如果完成读取
if(xmlHttp.readyState == 4)
{ //如果请求状态码为200
if(xmlHttp.status == 200)
{
var div = document.getElementById("div");
//接收服务器响应
var xmlDoc = xmlHttp.responseXML;
//解析服务器响应
var data = xmlDoc.getElementsByTagName("data")[0].firstChild.nodeValue;
div.innerHTML = "<i>"+data+"</i>";
}
}
}
</script>
</head>
<body>
<div id="div" style="display:flex;align-items: center;justify-content: center"></div>
<div align="center" style="width:100%">
<input type="button" value="获取后台数据" id="btn1" onclick="createXmlHttpRequest()">
</div>
</body>
</html>
- 后台:xml
<?xml version="1.0" encoding="UTF-8"?>
<HelloWorld>
<data>
HelloWorld from server!
</data>
</HelloWorld>
-
效果
2. 观察Ajax请求
- Ajax请求的类型为XHR,在header中可以找到
x-requested-with: XMLHttpRequest
。 - 打开浏览器 -> 打开网页 -> 按f12 - > 切换到netword选项卡 -> 切换到xhr子选项卡 -> 触发Ajax- > 获得请求
- 以头条网搜索(https://www.toutiao.com/search)为例。
-
通过观察请求内容,可以获得请求的url和参数。
4. 爬取Ajax数据
- 用Python模拟浏览器发出Ajax请求:
>>>import requests
>>>from urllib.parse import urlencode
>>>base_url = 'https://www.toutiao.com/api/search/content/?'
>>>headers={
>>> 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
>>> 'x-Requested-With':'XMLHttpRequest'
>>>}
>>>def get_page():
>>> # 获取ajax数据
>>> params = {
>>> 'aid':'24',
>>> 'app_name':'web_search',
>>> 'offset':'0',
>>> 'format':'json',
>>> 'keyword':'天问',
>>> 'autoload':'true',
>>> 'count':'20',
>>> 'en_qc':'1',
>>> 'cur_tab':'1',
>>> 'from':'search_tab',
>>> 'pd':'synthesis',
>>> 'timestamp':'1595555856284',
>>> '_signature':'dmnSBgAgEBCwPmuLZGUZj3ZokxAACl20erea8yVotjl6bt0QyPm3C0IitmjZPdNLeqVl - m. - Anc.JeDoNUPwmgSxIQAjLH87GiPqebGl3ewifL.FLPgoxpud29vpujvqaIt'
>>> }
>>> 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)
>>>if __name__ == '__main__':
>>> data = get_page()
>>> print(len(data))
26
- 解析数据:
>>>import requests
>>>from urllib.parse import urlencode
>>>base_url = 'https://www.toutiao.com/api/search/content/?'
>>>headers={
>>> 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
>>> 'x-Requested-With':'XMLHttpRequest'
>>>}
>>>def parse_page(func):
>>> # 解析数据
>>> def deco(*args, **kwargs):
>>> data = filter(lambda x:x.get('abstract'),func(*args, **kwargs).get('data')) # 获取并过滤数据
>>> result = []
>>> for d in data:
>>> message = {}
>>> message['title'] = d.get('title')
>>> message['from'] = d.get('media_name')
>>> message['datetime'] = d.get('datetime')
>>> message['read_count'] = d.get('read_count')
>>> result.append(message)
>>> return result
>>> return deco
>>>@parse_page
>>>def get_page():
>>> # 获取ajax数据
>>> params = {
>>> 'aid':'24',
>>> 'app_name':'web_search',
>>> 'offset':'0',
>>> 'format':'json',
>>> 'keyword':'天问',
>>> 'autoload':'true',
>>> 'count':'20',
>>> 'en_qc':'1',
>>> 'cur_tab':'1',
>>> 'from':'search_tab',
>>> 'pd':'synthesis',
>>> 'timestamp':'1595555856284',
>>> '_signature':'dmnSBgAgEBCwPmuLZGUZj3ZokxAACl20erea8yVotjl6bt0QyPm3C0IitmjZPdNLeqVl - m. - Anc.JeDoNUPwmgSxIQAjLH87GiPqebGl3ewifL.FLPgoxpud29vpujvqaIt'
>>> }
>>> 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)
>>>if __name__ == '__main__':
>>> data = get_page()
>>> for index,value in enumerate(data):
>>> print(f'第{index}条 标题:<<{value.get("title")}>> 媒体:{value.get("from")} 日期:{value.get("datetime")} 阅读量:{value.get("read_count")} ')
第0条 标题:<<屈原的天问及译文>> 媒体:律界诗者 日期:2020-07-23 21:14:28 阅读量:181
第1条 标题:<<上古奇文《天问》原文,屈原向上苍叩问宇宙本源>> 媒体:水煮歷史 日期:2018-10-24 14:21:55 阅读量:6850
第2条 标题:<<千古奇文:屈原《楚辞》中的《天问》>> 媒体:泽光书院 日期:2020-05-01 19:43:47 阅读量:491
第3条 标题:<<火星探测器为什么取名“天问”?第一时间解读火星探索 4 大问题>> 媒体:科学声音 日期:2020-07-24 10:27:47 阅读量:18
第4条 标题:<<屈原《天问》原文与释文>> 媒体:书画鉴赏典评收藏 日期:2019-05-04 21:05:38 阅读量:835
第5条 标题:<<天问一号成功发射,马斯克发推祝贺:令人惊叹>> 媒体:观察者网 日期:2020-07-23 18:01:08 阅读量:7764
第6条 标题:<<中国历史性一天!火星探测器“天问一号”发射成功,领先美国>> 媒体:智东西 日期:2020-07-23 14:03:21 阅读量:9509
第7条 标题:<<中国首次火星探测任务“天问一号”探测器成功发射,马斯克发推:令人惊叹>> 媒体:环球网 日期:2020-07-23 20:00:44 阅读量:1718
参考资料
- https://blog.csdn.net/u010138758/article/details/80152151 J-Ombudsman
- https://www.cnblogs.com/zhuluqing/p/8832205.html moisiet
- https://www.runoob.com 菜鸟教程
- http://www.tulingxueyuan.com/ 北京图灵学院
- http://www.imooc.com/article/19184?block_id=tuijian_wz#child_5_1 两点水
- https://blog.csdn.net/weixin_44213550/article/details/91346411 python老菜鸟
- https://realpython.com/python-string-formatting/ Dan Bader
- https://www.liaoxuefeng.com/ 廖雪峰
- https://blog.csdn.net/Gnewocean/article/details/85319590 新海说
- https://www.cnblogs.com/Nicholas0707/p/9021672.html Nicholas
- https://www.cnblogs.com/dalaoban/p/9331113.html 超天大圣
- https://blog.csdn.net/zhubao124/article/details/81662775 zhubao124
- https://blog.csdn.net/z59d8m6e40/article/details/72871485 z59d8m6e40
- 《Python学习手册》Mark Lutz
- 《Python编程 从入门到实践》Eric Matthes
- 《Python3网络爬虫开发实战》崔庆才
本文作者:大师兄(superkmi)
网友评论