左手用R右手Python系列——循环中的错误异常规避
上一讲讲了R语言与Pyhton中的异常捕获与错误处理基本知识,今天以一个小案例来进行实战演练,让你的程序遇水搭桥,畅通无阻。
本案例目标网址,今日头条的头条指数行业报告,全都是pdf格式的,需要先抓包获取PDF文件地址,之后我会随机抽取其中5个地址(因为PDF下载要看网速的,特别慢),然后将其中两个地址设置为不存在地址。
这种错误非常常见,当然实际应用中错误类型多种多样,需要你仔细甄别,但解决的基本思路都是这样的。当遇到一个错误地址导致程序遇阻时,使用异常函数先捕获错误异常,然后使用next命令进行绕过即可(Python中的next命令是continue)。
R语言循环中的错误处理:
library("httr")
library("dplyr")
library("jsonlite")
url<-"https://index.toutiao.com/api/report"
构建下载函数:
GETPDF<-function(url){
myresult<-data.frame()
headers<-c(
"Host"="index.toutiao.com",
"User-Agent"="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"
)
payload <-list("page"=1,"size"=12)
for (i in 1:16){
payload[["page"]]=i
web <- GET(url,add_headers(.headers = headers),query = payload,verbose())
content <- web %>% content(as="text",encoding="UTF-8") %>% fromJSON() %>% `[[`(9)
myresult <- rbind(myresult,content)
Sys.sleep(runif(1))
print(sprintf("正在抓取第 【%d】 页数据",i))
}
print("所有16页报告数据全部抓取完毕!!!")
return(myresult)
}
运行数据抓取函数:
myresult<-GETPDF(url)
#按照id排序
myresult<-arrange(myresult,id)
#将数据框中的PDF地址链接补全
myresult$path<-paste0("https://mlab.toutiao.com/report/download/",myresult$path)
#随机抽取其中5个标题和地址
Test<-myresult[sample(1:189,5),c("title","path")]
Test[5,2]'//mlab.toutiao.com/report/download/report47.pdf'
#将其中的第3、5个地址设置为越界地址(就是网址合法但是索引越界,那么你请求不到合法数据)
Test[3,2]<-"https://mlab.toutiao.com/report/download/report570.pdf"
Test[5,2]<-"https://mlab.toutiao.com/report/download/report470.pdf"
使用越界地址在浏览器中请求的返回界面是这样的!
接下来使用含有两个越界地址的向量进行PDF循环下载:
存在隐患的代码:
setwd("D:/R")
for(i in 1:nrow(Test)){
download.file(Test$path[i],paste0(Test$title[i],".pdf"), mode = "wb")
print(sprintf("正在打印第%d",i))
Sys.sleep(runif(1))
}
加入错误捕获的代码(方案1——使用tryCatch):
for(i in 1:nrow(Test)){
tryCatch({
download.file(Test$path[i],paste0(Test$title[i],".pdf"), mode = "wb")
print(sprintf("正在打印第【%d】",i))
},error = function(e) {
print(sprintf("第【%d】页地址无效,继续下一页!",i))
})
Sys.sleep(runif(1))
}
加入错误捕获的代码(方案1——使用try):
for (i in 1:nrow(Test)){
Error <- try(download.file(Test$path[i],paste0(Test$title[i],".pdf"), mode = "wb"))
if(!'try-error' %in% class(Error)){
download.file(Test$path[i],paste0(Test$title[i],".pdf"), mode = "wb")
print(sprintf("正在打印第【%d】",i))
} else {
print(sprintf("第【%d】页地址无效,继续下一页!",i))
next
}
Sys.sleep(runif(1))
}
以上两段代码都是合法的代码,输出了3个正确的PDF文档,tryCatch和try都可以用来绕过循环,tryCatch看起来更具有其他语言的通用排错风格,错误捕获之后会直接忽略错误项,跳到下一轮循环,try则是我们通过if判断,指定了错误项的处理方案是next(也就是忽略本次循环,直接跳转到下一个循环)。
但是如果你在不知情的情况下,不做任何异常处理,那么遇到错误链接导致进程阻塞,编辑器会自己弹出错误,然后中断进程,这是我们不愿意看到的。
Python:
import json
import random
import requests
import pandas as pd
import osimport time
仍然时先抓取PDF下载地址:
headers={
"Host":"index.toutiao.com",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"
}
payload ={"page":1,"size":12}
url="https://index.toutiao.com/api/report"
def GETPDF(url,headers=headers,payload=payload):
fullinfo=[]
for i in range(1,17):
payload['pageIndex']=i
r=requests.get(url,params=payload,headers=headers)
content=r.json()
fullinfo=fullinfo+content['data']
print("第{}部分已加载".format(i))
print("所有页面均以加载完!!!")
return fullinfo
mydata=GETPDF(url)
mydata=pd.DataFrame(mydata)
#随机选择5个记录:
Test=mydata.loc[:5,['title','path']]
#拼接成完整的下载链接
Test['path']=['https://mlab.toutiao.com/report/download/'+text for text in Test['path']]
#随机设置两个越界地址
Test['path'][[3,5]]='https://mla.toutiao.com/download/500.pdf'
os.chdir("D:/Python/File")
不设置任务错误捕获机制:
for i in range(len(Test)):
file=requests.get(Test['path'][i]).content
with open('{}.pdf'.format(Test['title'][i]), 'wb') as f:
f.write(file)
print("第{}个文件已下载完毕!!!".format(i))
time.sleep(1)
设置容错处理后的代码:
for i in range(len(Test)):
try:
file=requests.get(Test['path'][i]).content
with open('{}.pdf'.format(Test['title'][i]), 'wb') as f:
f.write(file)
print("第{}个文件已下载完毕!!!".format(i+1))
except requests.exceptions.ConnectionError as e:
print("第{}个文件下载失败,失败原因:n".format(i+1),e)
continue
time.sleep(0.5)
#保存这份数据,或许以后还有用!
mydata.to_csv("D:/Python/File/toutiaoreport.csv")
可以看到,R语言与Python的错误捕获与规避机制都很好理解,只要在合适的位置放置好错误捕获函数,并同时指定出错后的解决错误就可以了,通常在循环中下载二进制文件或者提取数据,使用R语言中的next或者Python中的continue函数可以成功绕过循环中的失败任务,从而保持整个进程一直进行到循环结束,自动退出!
往期案例数据请移步本人GitHub: https://github.com/ljtyduyu/DataWarehouse/tree/master/File
- (八)高性能服务器架构设计总结3——以flamigo服务器代码为例
- (八)高性能服务器架构设计总结4——以flamigo服务器代码为例
- SQL员工部门表综合查询60题
- 如何对Scala中集合(Collections)进行排序
- 小白教程——安装和使用PyCharm
- 如何在 Scala 中科学地操作 collection(一)集合类型与操作
- Redis 一二事(2) - 在spring中使用jedis 连接调试单机redis以及集群redis
- 用 Python 制作微信好友个性签名词云图
- 用 Python 查看微信好友位置信息
- 用 Python 分析微信好友性别比例
- FreeMarker静态模板结合spring展示
- 源码阅读之Vector
- 用 Python 实现聊天机器人
- 用 Python 实现雪花效果
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 手动搭建Hadoop分布式集群
- Ansible-安装配置
- React-Redux 100行代码简易版探究原理。
- Ansible-免密登录与主机清单Inventory
- 安装Ambari和HDP
- React中引入Vue3的@vue/reactivity 实现响应式状态管理
- Ansible Ad-Hoc与常用模块
- Ansible Playbook 初识
- Ansible Playbook 变量与 register 详解
- 初探 Spark ML 第一部分
- Ansible Facts 变量详解 添加用户账号Ansible 配置清单Inventory
- Ansible playbook 编程
- 前端工程师自检清单73答
- Ansible playbook Vault 加密
- MySQL主从复制