- 主要内容:
- 关于异步传输AJAX
- 什么是AJAX?
- AJAX基本原理
- AJAX服务端请求数据案例
- 实战案例:抓取某东图书评价
- 什么是异步数据加载
- AJAX的基本概念
- 如何获取异步数据使用的URL
- 抓取异步数据
- 项目实战:分析某东商城图书评论数据,并抓取这些数据
1、异步,请求和下载异步,不占用主线程,即使加载数据缓慢,不会出现页面卡顿
2、传输数据的格式,XML->JSON
AJAX基本原理
- 发送请求,Web端页面中实现业务逻辑与页面交互的JavaScript语言, IE7+、FireFox,Chrome,Safari浏览器等,需使用XMLHttpRequest对象发送请求,而IE7版本以下的浏览器需要使用下面的代码串讲Microsoft.XMLHTTP对象xmlhttp = new ActiveXObject(“Microsoft.XMLHTTP”)
- 解析响应,响应主要是指JSON格式的数据。
使用JSON.parse(result)得到JavaScript的JSON的数据
- 渲染页面
- 使用Flask框架模拟实现一个异步加载的页面。
页面使用模板显示,通过jQuery想服务端发送请求,获取数据后将数据显示在页面上
- 知道了异步传输的URl,就可以通过requests等网络去通过URL进行抓取,不过返回的数据格式不是HTML,也不是XML,而是JSON。
- 所以不能使用XPath和CSS选择器处理,而是使用json模块中的loads函数将字符串形式的JSON转换为Python字典
服务器端:
from flask import Flask,render_template
from flask import make_response
import json
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/data')
def data():
data = [
{'id':1,'name':'PyQt5(Python)实战视频课程'},
{'id':2,'name':'Electron实战'},
{'id':3, 'name': '征服C++ 11'},
{'id':4, 'name': '征服Flask'},
]
response = make_response(json.dumps(data))
return response
if __name__ == '__main__':
app.run(host = '0.0.0.0', port='1234')
html页面内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>异步加载页面</title>
<script src="/static/jquery.js"></script>
</head>
<body onload="onLoad()">
<h1>视频课程</h1>
<ul id="video_list">
<li>人工智能-机器学习实战视频课程</li>
<li>用C++和Go开发Node.js本地模块</li>
<li>Go Web实战视频教程</li>
<li>Python科学计算与图形渲染库视频教程</li>
</ul>
<script>
function onLoad()
{
$.get("/data", function(result){
data = JSON.parse(result)
for(var i = 0; i < data.length;i++) {
$('#video_list').append('' + data[i].name + '')
}
});
}
</script>
</body>
</html>
jquery.js文件内容:
可以自行到网上下载,博主用的是jquery1.7.2版本
请求客户端:
import requests
import json
from lxml import etree
result = requests.get('http://localhost:1234/data')
# 由于返回的数据包含中文(unicode编码),所以需要将其转码
print(result.text)
text = result.text.encode('utf-8').decode('unicode-escape')
print(text)
# 将字符串形式的JSON转换为Python字典
data = json.loads(text)
print('个数:',len(data))
# 输出返回的所有视频课程名称
for value in data:
print(value['name'])
通过url的形式可以请求到数据,不过数据是以json的形式存放
抓取的异步数据后,进行解析,在控制台输出数据:
-
首先进入某东图书的官网,选取一本图书
https://item.jd.com/12715627.html
-
F12进入开发者模式,找到异步传输的评论内容URL
这里将一个小技巧,打开F12审查元素后,会看到很多眼花缭乱的条目,一下子找不出哪一个是评论的异步传输url,先清除一下当前的条目,再点击页面上评论的按钮,再传输过来的就是关于评论的条目了,数量上也会少很多。
双击可以查看异步页面传输的是什么
异步数据的URL: https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=12715627&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1
-
对其进行请求,注意要加Cookie
注意:这里Cookie的获取,需要用自己的账号登录网页后再获取某东上自己的Cookie,如果没有登录,请求网页仍然会被拦截,所以在爬虫无法解析页面的时候,最好打印一下页面的内容,大多是因为请求头设置的不够完全导致无法请求到页面的代码。
复习:如果忘记了如何获取自己的Cookie,请复习查看requests网络库内容: 如何获取及设置Cookie. -
实 *** 代码:
这里的代码需要替换url,Cookie,再解析JSON的数据
import requests
import re
import json
import csv
import os
# 设置请求头(User-Agent)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 ',
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://item.jd.com/',
'Connection': 'keep-alive',
'Cookie': '替换成自己的Cookie',
'Host': 'club.jd.com'
}
# 限定抓取的评论数
fetch_comment_count = 15
# 设置代理
proxies = {
"https":"https://27.220.121.173:49508"
}
index = 0
page_index = 0
flag = True # 用于控制循环的退出
while flag:
url = '''https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=12417265&score=0&sortType=5&page={}&pageSize=10&isShadowSku=0&fold=1'''.format(page_index)
print(url)
page_index += 1
# html = reqests.get(url,headers=header,proxies=proxies
# 抓取评论页面
html = requests.get(url,headers)
# 获取抓取的内容,这里需要先按照iso-8859-1格式编码
text = str(html.content, encoding='iso-8859-1')
# 下面的代码替换返回数据的部分内容,因为返回的数据并不是标准的JSON格式
leftIndex = text.find('{')
rightIndex = text.rfind('}')
json_str = text.replace('fetchJSON_comment98(', '')
json_str = json_str.replace(")", '')
json_str = json_str.replace("null", '"null"')
json_str = json_str.replace(";", '')
print(json_str)
json_obj = json.loads(json_str)
# 循环输出评论数据
for i in range(0,len(json_obj['comments'])):
try:
# 这里要进行iso-8859-1编码,然后在解码,否则会出现乱码
# 按iso-8859-1编码是指按原样将字符转换为字节流
# 获取评论内容
comment = json_obj['comments'][i]['content'].encode(encoding='iso-8859-1').decode('GB18030')
# 删除评论内容是用户 没有填写评论内容
if comment != '此用户未填写评价内容':
print('<',index + 1,'>',comment)
# 获取评论时间
creationTime = json_obj['comments'][i]['creationTime']
# 获取昵称
nickname = json_obj['comments'][i]['nikename'].encode(encoding='iso-8859-1').decode('GB18030')
print(creationTime)
print(nickname) print('__________________________________________________________')
index += 1
except:
pass
if index == fetch_comment_count:
flag = False
break
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)