mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-24 20:00:37 +00:00
docs: Python 脚本实现爬取疫情数据并用 Markdown 预览
This commit is contained in:
@@ -1861,7 +1861,7 @@ iOS 网络现状是由4层组成的:最底层的 BSD Sockets、SecureTransport
|
||||
|
||||
|
||||
|
||||
#### 2.1 NSURLProtocol 监控 App 网络请求
|
||||
#### 2.1 NSURLProtocol 监控 App 网络请求<a name="network-2.1"></a>
|
||||
|
||||
NSURLProtocol 作为上层接口,使用较为简单,但 NSURLProtocol 属于 URL Loading System 体系中。应用协议的支持程度有限,支持 FTP、HTTP、HTTPS 等几个应用层协议,对于其他的协议则无法监控,存在一定的局限性。如果监控底层网络库 CFNetwork 则没有这个限制。
|
||||
|
||||
@@ -2341,9 +2341,9 @@ API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0))
|
||||
|
||||
|
||||
|
||||
#### 2.2 骚操作篇
|
||||
#### 2.2 骚操作篇 <a name="network-2.2"></a>
|
||||
|
||||
在 2.1 分析到了 NSURLSessionTaskMetrics 由于兼容性问题,对于网络监控来说似乎不太完美,但是自后在搜资料的时候看到了一篇[文章](https://www.jianshu.com/p/1c34147030d1)。文章在分析 WebView 的网络监控的时候分析 Webkit 源码的时候发现了下面代码
|
||||
文章上面 [2.1 ](#network-2.1)分析到了 NSURLSessionTaskMetrics 由于兼容性问题,对于网络监控来说似乎不太完美,但是自后在搜资料的时候看到了一篇[文章](https://www.jianshu.com/p/1c34147030d1)。文章在分析 WebView 的网络监控的时候分析 Webkit 源码的时候发现了下面代码
|
||||
|
||||
```objective-c
|
||||
#if !HAVE(TIMINGDATAOPTIONS)
|
||||
@@ -2441,9 +2441,9 @@ NSURLSession 在 iOS9 之前使用 `_setCollectsTimingData:` 就可以使用 Tim
|
||||
|
||||
在 iOS 中 AOP 的实现是基于 Runtime 机制,目前由3种方式:Method Swizzling、NSProxy、FishHook(主要用用于 hook c 代码)。
|
||||
|
||||
2.1 讨论了满足大多数的需求的场景,NSURLProtocol 监控了 NSURLConnection、NSURLSession 的网络请求,自身代理后可以发起网络请求并得到诸如请求开始时间、请求结束时间、header 信息等,但是无法得到非常详细的网络性能数据,比如 DNS 开始解析时间、DNS 解析用了多久、reponse 开始返回的时间、返回了多久等。 iOS10 之后 NSURLSessionTaskDelegate 增加了一个代理方法 `- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));`,可以获取到精确的各项网络数据。但是具有兼容性。2.2 讨论了一个 Webkit 源码中得到的信息,通过私有方法 `_setCollectsTimingData:` 、`_timingData` 可以获取到 TimingData。
|
||||
文章上面 [2.1 ](#network-2.1)讨论了满足大多数的需求的场景,NSURLProtocol 监控了 NSURLConnection、NSURLSession 的网络请求,自身代理后可以发起网络请求并得到诸如请求开始时间、请求结束时间、header 信息等,但是无法得到非常详细的网络性能数据,比如 DNS 开始解析时间、DNS 解析用了多久、reponse 开始返回的时间、返回了多久等。 iOS10 之后 NSURLSessionTaskDelegate 增加了一个代理方法 `- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));`,可以获取到精确的各项网络数据。但是具有兼容性。文章上面 [2.2 ](#network-2.2)讨论了从 Webkit 源码中得到的信息,通过私有方法 `_setCollectsTimingData:` 、`_timingData` 可以获取到 TimingData。
|
||||
|
||||
但是如果需要监全部的网络请求就不能满足需求了,查阅资料后发现了阿里百川有 APM 的解决方案,对于网络监控需要做如下的 hook
|
||||
但是如果需要监全部的网络请求就不能满足需求了,查阅资料后发现了阿里百川有 APM 的解决方案,于是有了方案3,对于网络监控需要做如下的处理
|
||||
|
||||

|
||||
|
||||
@@ -2546,7 +2546,292 @@ void printResponseData (CFDataRef responseData) {
|
||||
}
|
||||
```
|
||||
|
||||
Method Swizzling 方法替换需要知道类名,我们在开发阶段使用 NSURLConnection、NSURLSession 都需要指定代理对象,且代理对象在该阶段没有办法确定,所以在此处的思路是在 NSURLConnection、NSURLSession 设置代理的时候替换掉代理对象,
|
||||
我们知道 NSURLSession、NSURLConnection、CFNetwork 的使用都需要调用一堆方法进行设置然后需要设置代理对象,实现代理方法。所以针对这种情况进行监控首先想到的是使用 runtime hook 掉方法层级。但是针对设置的代理对象的代理方法没办法 hook,因为不知道代理对象是哪个类。所以想办法可以 hook 设置代理对象这个步骤,将代理对象替换成我们设计好的某个类,然后让这个类去实现 NSURLConnection、NSURLSession、CFNetwork 相关的代理方法。然后在这些方法的内部都去调用一下原代理对象的方法实现。所以我们的需求得以满足,我们在相应的方法里面可以拿到监控数据,比如请求开始时间、结束时间、状态码、内容大小等。
|
||||
|
||||
具体步骤及其关键代码如下,以 NSURLConnection 举例
|
||||
|
||||
- 因为要 Hook 挺多地方,所以写一个 method swizzling 的工具类
|
||||
|
||||
```objective-c
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (hook)
|
||||
|
||||
/**
|
||||
hook对象方法
|
||||
|
||||
@param originalSelector 需要hook的原始对象方法
|
||||
@param swizzledSelector 需要替换的对象方法
|
||||
*/
|
||||
+ (void)apm_swizzleMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector;
|
||||
|
||||
/**
|
||||
hook类方法
|
||||
|
||||
@param originalSelector 需要hook的原始类方法
|
||||
@param swizzledSelector 需要替换的类方法
|
||||
*/
|
||||
+ (void)apm_swizzleClassMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
+ (void)apm_swizzleMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector
|
||||
{
|
||||
class_swizzleInstanceMethod(self, originalSelector, swizzledSelector);
|
||||
}
|
||||
|
||||
+ (void)apm_swizzleClassMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector
|
||||
{
|
||||
//类方法实际上是储存在类对象的类(即元类)中,即类方法相当于元类的实例方法,所以只需要把元类传入,其他逻辑和交互实例方法一样。
|
||||
Class class2 = object_getClass(self);
|
||||
class_swizzleInstanceMethod(class2, originalSelector, swizzledSelector);
|
||||
}
|
||||
|
||||
void class_swizzleInstanceMethod(Class class, SEL originalSEL, SEL replacementSEL)
|
||||
{
|
||||
Method originMethod = class_getInstanceMethod(class, originalSEL);
|
||||
Method replaceMethod = class_getInstanceMethod(class, replacementSEL);
|
||||
|
||||
if(class_addMethod(class, originalSEL, method_getImplementation(replaceMethod),method_getTypeEncoding(replaceMethod)))
|
||||
{
|
||||
class_replaceMethod(class,replacementSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
|
||||
}else {
|
||||
method_exchangeImplementations(originMethod, replaceMethod);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 建立一个继承自 NSProxy 抽象类的类,实现相应方法。
|
||||
|
||||
```objective-c
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// 为 NSURLConnection、NSURLSession、CFNetwork 代理设置代理转发
|
||||
@interface NetworkDelegateProxy : NSProxy
|
||||
|
||||
+ (instancetype)setProxyForObject:(id)originalTarget withNewDelegate:(id)newDelegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
// .m
|
||||
@interface NetworkDelegateProxy () {
|
||||
id _originalTarget;
|
||||
id _NewDelegate;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NetworkDelegateProxy
|
||||
|
||||
#pragma mark - life cycle
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static NetworkDelegateProxy *_sharedInstance = nil;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
_sharedInstance = [NetworkDelegateProxy alloc];
|
||||
});
|
||||
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - public Method
|
||||
|
||||
+ (instancetype)setProxyForObject:(id)originalTarget withNewDelegate:(id)newDelegate
|
||||
{
|
||||
NetworkDelegateProxy *instance = [NetworkDelegateProxy sharedInstance];
|
||||
instance->_originalTarget = originalTarget;
|
||||
instance->_NewDelegate = newDelegate;
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)invocation
|
||||
{
|
||||
if ([_originalTarget respondsToSelector:invocation.selector]) {
|
||||
[invocation invokeWithTarget:_originalTarget];
|
||||
[((NSURLSessionAndConnectionImplementor *)_NewDelegate) invoke:invocation];
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel
|
||||
{
|
||||
return [_originalTarget methodSignatureForSelector:sel];
|
||||
}
|
||||
|
||||
@end
|
||||
```
|
||||
|
||||
- 创建一个对象,实现 NSURLConnection、NSURLSession、NSIuputStream 代理方法
|
||||
|
||||
```objective-c
|
||||
// NetworkImplementor.m
|
||||
|
||||
#pragma mark-NSURLConnectionDelegate
|
||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
|
||||
- (nullable NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response {
|
||||
NSLog(@"%s", __func__);
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark-NSURLConnectionDataDelegate
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten
|
||||
totalBytesWritten:(NSInteger)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
|
||||
#pragma mark-NSURLConnectionDownloadDelegate
|
||||
- (void)connection:(NSURLConnection *)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long) expectedTotalBytes {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
|
||||
- (void)connectionDidResumeDownloading:(NSURLConnection *)connection totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long) expectedTotalBytes {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *) destinationURL {
|
||||
NSLog(@"%s", __func__);
|
||||
}
|
||||
// 根据需求自己去写需要监控的数据项
|
||||
```
|
||||
|
||||
- 给 NSURLConnection 添加 Category,专门设置 hook 代理对象、hook NSURLConnection 对象方法
|
||||
|
||||
```objective-c
|
||||
// NSURLConnection+Monitor.m
|
||||
@implementation NSURLConnection (Monitor)
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
@autoreleasepool {
|
||||
[[self class] apm_swizzleMethod:@selector(apm_initWithRequest:delegate:) swizzledSelector:@selector(initWithRequest: delegate:)];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (_Nonnull instancetype)apm_initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate
|
||||
{
|
||||
/*
|
||||
1. 在设置 Delegate 的时候替换 delegate。
|
||||
2. 因为要在每个代理方法里面,监控数据,所以需要将代理方法都 hook 下
|
||||
3. 在原代理方法执行的时候,让新的代理对象里面,去执行方法的转发,
|
||||
*/
|
||||
NSString *traceId = @"traceId";
|
||||
NSMutableURLRequest *rq = [request mutableCopy];
|
||||
NSString *preTraceId = [request.allHTTPHeaderFields valueForKey:@"head_key_traceid"];
|
||||
if (preTraceId) {
|
||||
// 调用 hook 之前的初始化方法,返回 NSURLConnection
|
||||
return [self apm_initWithRequest:rq delegate:delegate];
|
||||
} else {
|
||||
[rq setValue:traceId forHTTPHeaderField:@"head_key_traceid"];
|
||||
|
||||
NSURLSessionAndConnectionImplementor *mockDelegate = [NSURLSessionAndConnectionImplementor new];
|
||||
[self registerDelegateMethod:@"connection:didFailWithError:" originalDelegate:delegate newDelegate:mockDelegate flag:"v@:@@"];
|
||||
|
||||
[self registerDelegateMethod:@"connection:didReceiveResponse:" originalDelegate:delegate newDelegate:mockDelegate flag:"v@:@@"];
|
||||
[self registerDelegateMethod:@"connection:didReceiveData:" originalDelegate:delegate newDelegate:mockDelegate flag:"v@:@@"];
|
||||
[self registerDelegateMethod:@"connection:didFailWithError:" originalDelegate:delegate newDelegate:mockDelegate flag:"v@:@@"];
|
||||
|
||||
[self registerDelegateMethod:@"connectionDidFinishLoading:" originalDelegate:delegate newDelegate:mockDelegate flag:"v@:@"];
|
||||
[self registerDelegateMethod:@"connection:willSendRequest:redirectResponse:" originalDelegate:delegate newDelegate:mockDelegate flag:"@@:@@"];
|
||||
delegate = [NetworkDelegateProxy setProxyForObject:delegate withNewDelegate:mockDelegate];
|
||||
|
||||
// 调用 hook 之前的初始化方法,返回 NSURLConnection
|
||||
return [self apm_initWithRequest:rq delegate:delegate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)registerDelegateMethod:(NSString *)methodName originalDelegate:(id<NSURLConnectionDelegate>)originalDelegate newDelegate:(NSURLSessionAndConnectionImplementor *)newDelegate flag:(const char *)flag
|
||||
{
|
||||
if ([originalDelegate respondsToSelector:NSSelectorFromString(methodName)]) {
|
||||
IMP originalMethodImp = class_getMethodImplementation([originalDelegate class], NSSelectorFromString(methodName));
|
||||
IMP newMethodImp = class_getMethodImplementation([newDelegate class], NSSelectorFromString(methodName));
|
||||
if (originalMethodImp != newMethodImp) {
|
||||
[newDelegate registerSelector: methodName];
|
||||
NSLog(@"");
|
||||
}
|
||||
} else {
|
||||
class_addMethod([originalDelegate class], NSSelectorFromString(methodName), class_getMethodImplementation([newDelegate class], NSSelectorFromString(methodName)), flag);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
```
|
||||
|
||||
|
||||
|
||||
这样下来就是可以监控到网络信息了,然后将数据交给数据上报 SDK,按照下发的数据上报策略去上报数据。
|
||||
|
||||
顺道说一句,上面针对 NSURLConnection、NSURLSession、NSInputStream 代理对象的 hook 之后,利用 NSProxy 实现代理对象方法的转发,有另一种方法可以实现,那就是 **isa swizzling**。
|
||||
|
||||
- Method swizzling 原理
|
||||
|
||||
```objective-c
|
||||
struct old_method {
|
||||
SEL method_name;
|
||||
char *method_types;
|
||||
IMP method_imp;
|
||||
};
|
||||
```
|
||||
|
||||

|
||||
|
||||
method swizzling 改进版如下
|
||||
|
||||
```objective-c
|
||||
Method originalMethod = class_getInstanceMethod(aClass, aSEL);
|
||||
IMP originalIMP = method_getImplementation(originalMethod);
|
||||
char *cd = method_getTypeEncoding(originalMethod);
|
||||
IMP newIMP = imp_implementationWithBlock(^(id self) {
|
||||
void (*tmp)(id self, SEL _cmd) = originalIMP;
|
||||
tmp(self, aSEL);
|
||||
});
|
||||
class_replaceMethod(aClass, aSEL, newIMP, cd);
|
||||
```
|
||||
|
||||
- isa swizzling
|
||||
|
||||
```objective-c
|
||||
/// Represents an instance of a class.
|
||||
struct objc_object {
|
||||
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
|
||||
};
|
||||
|
||||
/// A pointer to an instance of a class.
|
||||
typedef struct objc_object *id;
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
@@ -2556,7 +2841,7 @@ Method Swizzling 方法替换需要知道类名,我们在开发阶段使用 NS
|
||||
|
||||
|
||||
|
||||
#### 2.4 监控 App 常见网络请求
|
||||
#### 2.4 监控 App 常见网络请求<a name="categoryNameRules"></a>
|
||||
|
||||
本着成本的原因,由于现在大多数的项目的网络能力都是通过 [AFNetworking](https://github.com/AFNetworking/AFNetworking) 完成的,所以本文的网络监控可以快速完成。
|
||||
|
||||
|
||||
@@ -407,10 +407,10 @@ if ([cls respondsToSelector:sel]) {
|
||||
6. 网络请求完成后,通过 NetworkProtocolClient 将请求结果返回给 WKWebView。
|
||||
|
||||
|
||||
### 5. 拦截 WebView 内 Ajax 请求
|
||||
|
||||
|
||||
|
||||
|
||||
其实上述的方法也是可行,不过使用私有 API 的方式不是很推荐,一般在穷途末路的时候才选择私有 API,所以另一种思路是 hook Web 端的 ajax 请求。在执行 hook 后的 ajax 请求的时候将 ajax 的请求相关信息(请求方式、header、body 等)以 messageHandler 的方式告诉 Native,然后起到监控的效果。
|
||||
参考: https://www.jianshu.com/p/7337ac624b8e;https://github.com/wendux/Ajax-hook
|
||||
|
||||
|
||||
|
||||
|
||||
106
Chapter3 - Server/3.9.md
Normal file
106
Chapter3 - Server/3.9.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# 爬取疫情数据并用 Markdown 预览
|
||||
|
||||
> 周五不困,无聊写了一个 Python 脚本,功能很简单:获取新浪关于各个国家疫情数据,并写入 md 文件并预览,定时去获取数据,有新数据则生成新的 markdown 内容拼接在文件最后。
|
||||
|
||||
|
||||
|
||||
|
||||
## 一、 代码
|
||||
|
||||
由于功能和代码都很简单,直接上代码
|
||||
|
||||
```Python
|
||||
# -*-coding:utf8-*-
|
||||
import re,requests,json,pprint,time
|
||||
import os
|
||||
|
||||
pattern=re.compile(r'^try{sinajp_15844213244528328543098388435\((.*?)\);}catch\(e\){};')
|
||||
lasttimes='00:00:00'
|
||||
|
||||
while True:
|
||||
res=requests.get('https://gwpre.sina.cn/ncp/foreign?_=1584421324452&callback=sinajp_15844213244528328543098388435')
|
||||
match=pattern.search(res.text)
|
||||
|
||||
if match:
|
||||
obj=json.loads(match.group(1))
|
||||
resultObj=obj['result']
|
||||
times=resultObj['times'] # 截止时间
|
||||
timesMatch=re.search(r'截至(\d{2})月(\d{2})日(\d{2})时(\d{2})分',times)
|
||||
if timesMatch:
|
||||
times=timesMatch.group(1)+'月'+timesMatch.group(2)+'日 '+timesMatch.group(3)+':'+timesMatch.group(4)
|
||||
|
||||
if times==lasttimes:
|
||||
continue
|
||||
else:
|
||||
lasttimes=times
|
||||
totalObj=resultObj['total']
|
||||
certain=totalObj['certain'] # 累计确诊
|
||||
die=totalObj['die'] # 死亡
|
||||
recure=totalObj['recure'] # 治愈
|
||||
certain_inc=totalObj['certain_inc'] # 确诊增加
|
||||
die_inc=totalObj['die_inc'] # 死亡增加
|
||||
recure_inc=totalObj['recure_inc'] # 治愈增加
|
||||
# 各国数据列表
|
||||
worldlistArr=resultObj['worldlist']
|
||||
worldlistArr.sort(key=lambda x: int(x.get('conNum','0')),reverse=True)
|
||||
|
||||
fo=open('./coronavirus.md','a')
|
||||
fo.writelines('\n# '+times+'\n')
|
||||
fo.writelines('感染国家总数:'+str(len(worldlistArr))+'\n')
|
||||
fo.writelines('```\n累计确诊:'+certain.rjust(10,' ')+' 较昨日:'+certain_inc+'\n'+'累计死亡:'+die.rjust(10,' ')+' 较昨日:'+die_inc+'\n'+'累计治愈:'+recure.rjust(10,' ')+' 较昨日:'+recure_inc+'\n```\n')
|
||||
|
||||
fo.writelines('|国家|新增确诊|累计确诊|新增死亡|累计死亡|累计治愈|'+'\n')
|
||||
fo.writelines('|:--:|---:|---:|---:|---:|---:|'+'\n')
|
||||
|
||||
top15=worldlistArr[:15]
|
||||
pattient_countrys=['澳大利亚','加拿大','巴西','印度','丹麦','越南','新加坡','俄罗斯','塞尔维亚','巴基斯坦',]
|
||||
pattient=[c for c in worldlistArr if c['name'] in pattient_countrys]
|
||||
|
||||
for countryObj in top15:
|
||||
name=countryObj['name'] # 国家
|
||||
if name=='中国':
|
||||
continue
|
||||
conadd=countryObj['conadd'] # 新增确诊
|
||||
conNum=countryObj['conNum'] # 累计确诊
|
||||
deathadd=countryObj['deathadd'] # 新增死亡
|
||||
deathNum=countryObj['deathNum'] # 累计死亡
|
||||
cureNum=countryObj['cureNum'] # 累计治愈
|
||||
fo.writelines('|'+name+'|'+conadd+'|'+conNum+'|'+deathadd+'|'+deathNum+'|'+cureNum+'|\n')
|
||||
|
||||
fo.writelines('\n特别关心'+'\n')
|
||||
fo.writelines('|国家|新增确诊|累计确诊|新增死亡|累计死亡|累计治愈|'+'\n')
|
||||
fo.writelines('|:--:|---:|---:|---:|---:|---:|'+'\n')
|
||||
for countryObj in pattient:
|
||||
name=countryObj['name'] # 国家
|
||||
conadd=countryObj['conadd'] # 新增确诊
|
||||
conNum=countryObj['conNum'] # 累计确诊
|
||||
deathadd=countryObj['deathadd'] # 新增死亡
|
||||
deathNum=countryObj['deathNum'] # 累计死亡
|
||||
cureNum=countryObj['cureNum'] # 累计治愈
|
||||
fo.writelines('|'+name+'|'+conadd+'|'+conNum+'|'+deathadd+'|'+deathNum+'|'+cureNum+'|\n')
|
||||
fo.close()
|
||||
|
||||
# 用 Markdown IDE 打开 .md 文件进行预览
|
||||
os.system('open -a "/Applications/Typora.app" ./coronavirus.md')
|
||||
|
||||
for i in range(1,61):
|
||||
time.sleep(10)
|
||||
print(i*10)2
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## 二、 如何使用
|
||||
|
||||
1. 安装 requests
|
||||
```shell
|
||||
pip3 install requests
|
||||
```
|
||||
|
||||
2. 修改 Markdown 的打开方式。由于我电脑安装 Marodown 编辑器是 `Typora`,所以脚本是 `open -a "/Applications/Typora.app" ./coronavirus.md`。修改这里的 `***.app` 为自己的 ide
|
||||
|
||||
3. 终端运行即可
|
||||
```shell
|
||||
python3 coronavirus.py
|
||||
```
|
||||
@@ -11,3 +11,4 @@
|
||||
* [6、YAML](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.6.md)
|
||||
* [7、Node单元测试](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.7.md)
|
||||
* [8、数据安全(反爬虫)之「防重放」策略](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.8.md)
|
||||
* [9、爬取疫情数据并用 Markdown 预览](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.9.md)
|
||||
@@ -138,6 +138,7 @@
|
||||
* [6、YAML](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.6.md)
|
||||
* [7、Node单元测试](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.7.md)
|
||||
* [8、数据安全(反爬虫)之「防重放」策略](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.8.md)
|
||||
* [9、爬取疫情数据并用 Markdown 预览](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.9.md)
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
assets/2020-04-09-methodSwizzling.png
Normal file
BIN
assets/2020-04-09-methodSwizzling.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Reference in New Issue
Block a user