python3编写网络爬虫13-Ajax数据爬取
一、Ajax数据爬取
1. 简介:Ajax 全称Asynchronous JavaScript and XML 异步的Javascript和XML。
它不是一门编程语言,而是利用JavaScript在保证页面不被刷新,页面链接不改变的情况下与服务器交换数据,
获得数据后,再利用JavaScript改变页面。
示例:新浪微博 热门
2. 基本原理
2.1 发送请求
JavaScript可以实现页面交互功能 Ajax也不例外 它是由JavaScript实现的,实际上执行了如下代码
var xmlhttp;
if(window.XMLHttpRequest){
# code for IE7+,Firefox,Chrome,Opera,Safari
xmlhttp = new XMLHttpRequest();#新建对象
}else{#code for IE6,IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} xmlhttp.onreadystatechange = function(){#设置监听
if(xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("POST","/ajax/",true);
xmlhttp.send();#发送请求
这是javascript对ajax最底层的实现,新建XMLHttpRequest对象 调用onreadystatechange属性设置监听
调用open和send方法发送请求。
之前用python发送请求可以得到响应结果 但这里的请求发送变成了javascript来完成,
由于设置了监听 服务器响应结果时,onreadystatechange属性会被触发 然后解析里面的内容。
2.2 解析内容
得到响应内容后,onreadystatechange属性对应的方法便会触发,利用xmlhttp的responseText属性接收。
类似python中利用requests向服务器发送请求 然后得到响应结果的过程。
返回的结果可能是HTML 也可能是JSON 只需要在js中做进一步处理 例如返回json 可以进行解析和转化。
2.3 渲染页面
js有改变网页内容的能力,解析完响应内容后 调用js里面document.getElementById().innerHTML 改变某个元素内的源代码
这样网页的内容就改变了 简称DOM操作
2.4 总结 3个步骤都是js完成的 微博下拉实际上就是js向服务器发送一个Ajax请求 然后获取服务器响应内容
解析并渲染到网页中。真实数据都是js一次次ajax请求得到的。
如果需要抓取数据 就要知道 请求怎么发送的? 发送到哪里?发送了哪些参数?
3. Ajax分析方法
3.1 查看方法
测试地址:
https://m.weibo.cn/u/1195242865
浏览器开发者工具 ajax请求类型为xhr
Request Headers信息为 X-Requested-With: XMLHttpRequest 标记此请求为Ajax请求
3.2 过滤请求
点击开发者工具Network -> XHR 过滤为ajax请求 不断滑动页面 出现新的请求
发送请求地址:
https://m.weibo.cn/api/container/getIndex?type=uid&value=1195242865&containerid=1076031195242865&since_id=4311085060664535
参数:
type: uid
value: 1195242865
containerid: 1076031195242865
page:1
4. 提取结果
from urllib.parse import urlencode
import requests
from pyquery import PyQuery as pq base_url = 'https://m.weibo.cn/api/container/getIndex?'#请求url的前半部分 headers = {
'Host':'m.weibo.cn',
'Referer': 'https://m.weibo.cn/u/1195242865',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
} # 构造url 发送请求
def get_page(page):
params = {
'type': 'uid',
'value': '',
'containerid': '',
'page':page,
}
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) #解析方法 提取id 正文 赞数 评论数 转发数 遍历cards 获取mblog中的各个信息 def parse_page(json):
if json:
items = json.get('data').get('cards')
for item in items:
# print(item)
item = item.get('mblog')
if item:
weibo = {} #定义空字典接收数据
weibo['id'] = item.get('id')
weibo['text'] = pq(item.get('text')).text()
weibo['attitudes'] = item.get('attitudes_count')
weibo['comments'] = item.get('comments_count')
weibo['reposts'] = item.get('reposts_count')
yield weibo #遍历page 一共10页 将提取到的结果打印输出 if __name__ == '__main__':
for page in range(1,3):
json = get_page(page)
results = parse_page(json)
for result in results:
print(result)
5. 添加到mongodb数据库中
from pymongo import MongoClient client = MongoClient()
db = client['weibo']
collection = db['weibo'] def save_to_mongo(result):
if collection.insert(result):
print('Saved to Mongo')
查看mongo内容
启动mongo服务 查看库 show dbs; 查看当前在哪个库 db.getName(); 进入库 use dbname;
查看数据 db.dbname.find(); 删除当前所在库 db.dropDatabase();
至此分析模拟Ajax请求爬取微博列表完成 爬取结果不重要 还有好多地方可以完善 比如动态计算页码,查看微博全文等等。
主要是让大家了解抓取原理
实例:爬取今日头条街拍图片
地址:http://www.toutiao.com 关键字 :街拍
offset: 0
format: json
keyword: 街拍
autoload: true
count: 20
cur_tab: 1
from: search_tab
pd: synthesis
基本代码
import requests
import json
import time
import re
import os
from random import choice
from hashlib import md5 url = "https://www.toutiao.com/search_content/?"
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36',
}
keyword = '街拍' has_gallery_lists = []
no_gallery_lists = [] def SearchPageParser(offset=0):
payload = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': 30,
'cur_tab': 1,
'from': 'search_tab'
} count = 0 try:
response = requests.get(url, headers=header, params=payload)
content = None
#打印拼接请求后的url
# print("Parser " + response.url)
if response.status_code == requests.codes.ok:
content = response.text
data = json.loads(content) if not data:
return for article in data.get('data'):
if True == article.get('has_gallery') and True == article.get('has_image'):
has_gallery_lists.append(article.get('article_url'))
count += 1 if False == article.get('has_gallery') and True == article.get('has_image'):
no_gallery_lists.append(article.get('article_url'))
count += 1 return count except Exception as e:
print(e)
return #保存本地函数
def SaveImage(imageURL,title):
#判断文件夹是否存在
if not os.path.exists(title):
os.mkdir(title)
try:
response = requests.get(imageURL)
if response.status_code == 200:
file_path = '{0}/{1}.{2}'.format(title, md5(response.content).hexdigest(), 'jpg')
# 判断是否重名
if not os.path.exists(file_path):
with open(file_path,'wb') as f:
f.write(response.content)
else:
print('Already Downloaded',file_path)
except:
print('Failed to Save Image') #第一种页面
def HasGalleryParser():
if 0 == len(has_gallery_lists):
return # 正则
pattern = re.compile('gallery: JSON\.parse\("(.*?)max_img', re.S)
pattern_t = re.compile('<title>(.*?)</title>', re.S) while has_gallery_lists:
this = has_gallery_lists.pop() try:
response = requests.get(this, headers=header)
content = None if response.status_code == requests.codes.ok:
content = response.text
data = pattern.findall(content)
pattern_t.findall(content) if data:
#去掉多余符号
data = data[0][:-4].replace('\\', '') + ']}'
img_urls = json.loads(data).get('sub_images')
title = "".join(pattern_t.findall(content))
for img_url in img_urls:
#保存函数
SaveImage(img_url.get('url'),title)
else:
print("BadPageURL[GalleryParser, {0:s}]".format(this)) except Exception as e:
print(e)
return time.sleep(0.25) #第二种页面
def NoGalleryParser():
if 0 == len(no_gallery_lists):
return while no_gallery_lists:
this = no_gallery_lists.pop()
#正则匹配
pattern = re.compile('<img src="(.*?)"', re.S)
pattern_t = re.compile('<title>(.*?)</title>',re.S)
try:
response = requests.get(this, headers=header)
content = None if response.status_code == requests.codes.ok:
content = response.text
img_urls = pattern.findall(content)
img_title = "".join(pattern_t.findall(content))
if img_urls:
for img_url in img_urls:
#保存函数
SaveImage(img_url,img_title)
else:
# 过滤地址
print("BadPageURL[NoGalleryParser, {0:s}]".format(this)) except Exception as e:
print(e)
return time.sleep(0.25) if __name__ == "__main__":
#计数变量
x, count = 0, 0
# 获取头条页面
cnt_urls = SearchPageParser(x) while count < 20 and cnt_urls:
cnt_urls = SearchPageParser(x + 20)
count += cnt_urls
x += 20
time.sleep(0.55)
#打印分页地址
# print("Get {0:d} URL(s) in total.".format(count))
# 分析页面
HasGalleryParser()
NoGalleryParser()
python3编写网络爬虫13-Ajax数据爬取的更多相关文章
- python3编写网络爬虫16-使用selenium 爬取淘宝商品信息
一.使用selenium 模拟浏览器操作爬取淘宝商品信息 之前我们已经成功尝试分析Ajax来抓取相关数据,但是并不是所有页面都可以通过分析Ajax来完成抓取.比如,淘宝,它的整个页面数据确实也是通过A ...
- 第十四节:Web爬虫之Ajax数据爬取
有时候在爬取数据的时候我们需要手动向上滑一下,网页才加载一定量的数据,但是网页的url并没有发生变化,这时我们就要考虑使用ajax进行数据爬取了...
- Ajax数据爬取
Ajax的基本原理 以菜鸟教程的代码为例: XMLHTTPRequest对象是JS对Ajax的底层实现: var xmlhttp; if (window.XMLHttpRequest) { // IE ...
- 爬虫1.5-ajax数据爬取
目录 爬虫-ajax数据爬取 1. ajax数据 2. selenium+chromedriver知识准备 3. selenium+chromedriver实战拉勾网爬虫代码 爬虫-ajax数据爬取 ...
- python3编写网络爬虫14-动态渲染页面爬取
一.动态渲染页面爬取 上节课我们了解了Ajax分析和抓取方式,这其实也是JavaScript动态渲染页面的一种情形,通过直接分析Ajax,借助requests和urllib实现数据爬取 但是javaS ...
- 爬虫—Ajax数据爬取
一.什么是Ajax 有时候我们使用浏览器查看页面正常显示的数据与使用requests抓取页面得到的数据不一致,这是因为requests获取的是原始的HTML文档,而浏览器中的页面是经过JavaScri ...
- python3编写网络爬虫21-scrapy框架的使用
一.scrapy框架的使用 前面我们讲了pyspider 它可以快速的完成爬虫的编写 不过pyspider也有一些缺点 例如可配置化不高 异常处理能力有限对于一些反爬虫程度非常强的网站 爬取显得力不从 ...
- python3编写网络爬虫23-分布式爬虫
一.分布式爬虫 前面我们了解Scrapy爬虫框架的基本用法 这些框架都是在同一台主机运行的 爬取效率有限 如果多台主机协同爬取 爬取效率必然成倍增长这就是分布式爬虫的优势 1. 分布式爬虫基本原理 1 ...
- Python网络爬虫——Appuim+夜神模拟器爬取得到APP课程数据
一.背景介绍 随着生产力和经济社会的发展,温饱问题基本解决,人们开始追求更高层次的精神文明,开始愿意为知识和内容付费.从2016年开始,内容付费渐渐成为时尚. 罗辑思维创始人罗振宇全力打造" ...
随机推荐
- 深度学习之PyTorch实战(1)——基础学习及搭建环境
最近在学习PyTorch框架,买了一本<深度学习之PyTorch实战计算机视觉>,从学习开始,小编会整理学习笔记,并博客记录,希望自己好好学完这本书,最后能熟练应用此框架. PyTorch ...
- wepack---预打包dll
一.前言 今天被问到,怎么实现webpack快速打包?话说距离上次手动配置webpack已经过去很长时间了,现在webpack都出到4.0版本了,号称零配置,还没来得及好好感受一下. ‘不就是公共模块 ...
- Docker系列之Docker镜像(读书笔记)
一.基本概念 Docker包括三个基本概念镜像.容器.仓库. Docker镜像:就是一个只读的模板.例如:一个镜像可以包含一个完整的ubuntu操作系统环境,里面仅安装了Apache或其他应用程序.用 ...
- .NET常用开发工具整理
版本控制和项目管理工具 VisualSVN和AnkhSVN:两款在Visual Studio中管理Subversion的插件.. NuGet和NuGetPackageExplorer:一组用于自动执行 ...
- mysql查看执行sql语句的记录日志
开启日志模式 -- 1.设置 -- SET GLOBAL log_output = 'TABLE';SET GLOBAL general_log = 'ON'; //日志开启 -- SET GLOB ...
- c#:HttpClient加标头
using (var client = new HttpClient()) { string requestUrl = string.Format("{0}{1}", ConstD ...
- 菜鸟入门【ASP.NET Core】9:RoutingMiddleware介绍以及MVC引入
前言 前面介绍了使用app.Map来配置路由,但是对于一般不是特别大的项目来说,不使用Map来进行路由配置. 配置路由 我们首先需要在Startup.cs文件中的ConfigureServices方法 ...
- ModBus通信协议的【Modbus RTU 协议使用汇总】
1.RTU模式 当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符.这种方式的主要优点是:在同样的波特率下,可比ASCII方式传 ...
- Linux-kill命令和killall命令(11)
kill:指定将信号发送给某个进程,常用来杀掉进程,可以通过ps.top命令来查看进程 在默认情况下: 采用编号为的TERM信号.TERM信号将终止所有不能捕获该信号的进程. 对于那些可以捕获该信号的 ...
- Java基础——Oracle(五)
一.Oracle 中的分页 1) select * from emp; 2)select * ,rownum from emp; //这样写不行 3)select ename,job,sal,row ...