跳到主要内容

· 1 分钟阅读
Allen Ma

项目二:分析我国近25年来农村居民与城市居民享受基本公共卫生服务的变化情况(图表输出)

利用世界银行公开数据

# -*- coding: utf-8 -*-
"""
Created on Mon Sept 21 8:04:59 2020

@author: mly
"""
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import pandas as pd
from matplotlib import ticker

plt.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams["axes.unicode_minus"] = False

df = pd.read_csv('basicsanit_china2000to2017.csv')

y = df['rural_sanit']
y1 = df['urban_sanit']
y2 = df['peopl_sanit']
x = df['year']

plt.figure()
ax = plt.gca()
plt.grid(axis="y")
plt.title('农村居民与城市居民享受基本公共卫生服务的变化情况')
plt.ylabel('服务数值')
plt.xlabel('年份')
ax.plot(x, y, '-rp', lw = 1.5, label = 'rural_sanit')
ax.plot(x, y1, '-gp', lw = 1.5, label = 'rural_sanit')
ax.plot(x, y2, '-bp', lw = 1.5, label = 'peopl_sanit')
ax.legend(loc = 'upper right')

plt.show()

运行结果:

在这里插入图片描述

· 2 分钟阅读
Allen Ma

项目二:用两种不同的方法爬取股票数据

方法一:requests&bs4&re

import requests
from bs4 import BeautifulSoup
import re


def getHTMLText(url, code="utf-8"):
kv = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
try:
r = requests.get(url, headers=kv)
r.raise_for_status()
r.encoding = code
return r.text
except:
return ""


def getStockList(lst, stockURL):
html = getHTMLText(stockURL, "GB2312")
soup = BeautifulSoup(html, 'html.parser')
li = soup.find('section', attrs={'class': 'stockTable'})
a = li.find_all('a')
for i in a:
try:
href = i.attrs['href']
lst.append(re.findall(r"[S][HZ]\d{6}", href)[0])
except:
continue


def getStockInfo(lst, stockURL, fpath):
count = 0
for stock in lst:
url = stockURL + stock
html = getHTMLText(url)
try:
if html == "":
continue
infoDict = {}
soup = BeautifulSoup(html, 'html.parser')
stockInfo = soup.find('section', attrs={'class': 'stock_price clearfix'})
mc = soup.find('header', attrs={'class': 'stock_title'})
name = mc.find('h1')
infoDict.update({'股票名称': name.text})

keyList = stockInfo.find_all('dt')
valueList = stockInfo.find_all('dd')
for i in range(len(keyList)):
key = keyList[i].text
val = valueList[i].text
infoDict[key] = val

with open(fpath, 'a', encoding='utf-8_sig') as f:
f.write(str(infoDict) + '\n')
count = count + 1
print("\r当前进度: {:.2f}%".format(count * 100 / len(lst)), end="")
except:
count = count + 1
print("\r当前进度: {:.2f}%".format(count * 100 / len(lst)), end="")
continue


def main():
stock_list_url = 'https://hq.gucheng.com/gpdmylb.html'
stock_info_url = 'https://hq.gucheng.com/'
output_file = 'BaiduStockInfo.csv'
slist = []
getStockList(slist, stock_list_url)
getStockInfo(slist, stock_info_url, output_file)


main()

项目运行需要一段时间,可以通过输出台查看进度。

在这里插入图片描述 一个多小时后。。。执行完了 一共3590条数据 在这里插入图片描述

· 2 分钟阅读
Allen Ma

当我在使用SQL数据库作为数据来源时,发现所获取的多为时间序列数据,我就非常希望画以时间为横坐标的折线图。并希望自由地设置时间间隔,和画布大小。

import matplotlib.pyplot as plt
import pandas as pd
import pymssql
import warnings
from pylab import *
import matplotlib.dates as mdates

warnings.filterwarnings('ignore')

connect = pymssql.connect('IP地址','用户名','密码','数据库名')
print("连接成功")
data = pd.read_sql("select TRADEDATE,cast(TCLOSE as int) from TQ_QT_SKDAILYPRICE where SECODE='2010000512'", con=connect)
#print(data.head()) #查看读取的结果
data.columns = ['day','close']
#print(data.head()) #查看读取的结果
data['day'] = pd.to_datetime(data['day']) #轉換為日期,否則下面的日期設置不會生效

#matplotlib.pyplot方式
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']

fig = plt.figure(figsize=(20, 5))
ax = fig.add_subplot(1, 1, 1)

plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) #設置x軸主刻度顯示格式(日期)
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=15)) #設置x軸主刻度間距

plt.xlabel('日期')
plt.ylabel('收盘价')
plt.title('2010000512收盘价折线图')
plt.plot(data['day'],data['close'])
plt.show()

运行结果: 在这里插入图片描述

调节画布大小

fig = plt.figure(figsize=(20, 5))

20和5分别为画布的长宽。

控制中文字符和正负号正常显示

plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']

设置x轴主刻度显示格式(日期)

import matplotlib.dates as mdates
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))

'%Y-%m'可以从‘%y-%m-%d %H:%M’之中自由选择。分别显示年、月、日、时、分。

设置x轴主刻度间距

import matplotlib.dates as mdates
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=15))

通过更改interval的赋值大小改变横坐标标注的疏密程度。越大越稀疏。

· 2 分钟阅读
Allen Ma

可视化计算是数据分析的重要组成部分,特别是模块matplotlib。

最近新一代绘图模块plotly横空出世,在互动性上具有绝对的优势。但绘制一些简单的图像还是使用matplotlib比较方便。

2017年matplotlib2.0发布,提供了六种绘图风格供用户选择。

'bmh','dark_background','fivethirtyeight','ggplot','grayscale','default'

不同的集成环境可以将matplotlib的绘图风格增加到20多种。 这些方法可以直接运用到pandas的绘图语句中。

使用pandas数据分析模块内置的plot命令绘制图像,代码如下:

#coding=utf-8
'''
Created on 2020.09.29
'''
import matplotlib.pyplot as plt
import pandas as pd

def dr_xtyp(_dat):
#xtyp=['bmh','dark_background','fivethirtyeight','ggplot','grayscale','default']
for xss in plt.style.available:
plt.style.use(xss);print(xss)
_dat['Open'].plot()
_dat['Close'].plot()
_dat['High'].plot()
_dat['Low'].plot()
fss="tmp\\stk001_"+xss+"_pd.png";plt.savefig(fss)
plt.show()

# =======================
df = pd.read_csv('dat\\appl2014.csv',index_col=0,parse_dates=[0],encoding='gbk')

d30=df[:30]
dr_xtyp(d30)

运行结果:

在这里插入图片描述 在tmp目录下会产生各种不同风格的图像。

在这里插入图片描述

· 4 分钟阅读
Allen Ma

项目二:用两种不同的方法爬取股票数据

方法二:scrapy爬虫框架

此案例是运用scrapy框架对相关内容进行抓取。

安装scrapy框架

打开cmd,输入以下代码进行安装:

pip install scrapy

验证是否安装成功:

scrapy -h

创建一个新的Scrapy爬虫工程

scrapy安装成功后,继续在cmd里输入代码创建工程。 将目录切换到想要创建爬虫项目的路径下,执行:

scrapy startproject baidustocks

执行完毕后,会在目录下生成一系列文件夹和.py等文件。 在这里插入图片描述

在工程中产生一个Scrapy爬虫

只需要在cmd中输入一行命令,我们需要指定爬虫的名字和爬取的网站。

cd baidustocks
scrapy genspider stocks hq.gucheng.com/gpdmylb.html

stocks为爬虫名 hq.gucheng.com/gpdmylb.html为爬取网站

完成后会生成一个名叫stocks.py的文件。

配置产生的spider爬虫

安照自己的需求修改该爬虫文件。 我以爬取股票数据为例:

# -*- coding: utf-8 -*-

import scrapy
import re
from scrapy.selector import Selector


class StocksSpider(scrapy.Spider):
name = 'stocks'
start_urls = ['https://hq.gucheng.com/gpdmylb.html']

def parse(self, response):
for href in response.css('a::attr(href)').extract():
try:
stock = re.search(r'S[HZ]\d{6}/', href)
url = 'https://hq.gucheng.com/' + stock.group()
yield scrapy.Request(url, callback=self.parse_stock)
except:
continue

def parse_stock(self, response):
infoDict = dict()
stockInfo = response.css('.stock_top').extract()[0]
stockprice = response.css('.s_price').extract()[0]
stockname = response.css('.stock_title').extract()[0]
stockname = Selector(text=stockname)
stockprice = Selector(text=stockprice)
stockInfo = Selector(text=stockInfo)
infoDict['名字'] = re.search(r'>(.*?)</h1>', stockname.css('h1').extract()[0]).group(1)
infoDict['编号'] = re.search(r'>(.*?)</h2>', stockname.css('h2').extract()[0]).group(1)
infoDict['状态'] = re.search(r'>(.*?)</em>', stockname.css('em').extract()[0]).group(1)
infoDict['时间'] = re.search(r'>(.*?)</time>', stockname.css('time').extract()[0]).group(1)
price = stockprice.css('em').extract()
infoDict['股价'] = re.search(r'>(.*?)</em>', price[0]).group(1)
infoDict['涨跌额'] = re.search(r'>(.*?)</em>', price[1]).group(1)
infoDict['涨跌幅'] = re.search(r'>(.*?)</em>', price[2]).group(1)
keylist = stockInfo.css('dt').extract()
valuelist = stockInfo.css('dd').extract()
for i in range(len(keylist)):
key = re.search(r'>(.*?)<', keylist[i], flags=re.S).group(1)
key = str(key)
key = key.replace('\n', '')
try:
val = re.search(r'>(.*?)<', valuelist[i], flags=re.S).group(1)
val = str(val)
val = val.replace('\n', '')
except:
val = '--'
infoDict[key] = val
yield infoDict

运行爬虫,获取数据

cmd执行以下命令

scrapy crawl stocks

等待执行完毕可以看到的汇总信息: 在这里插入图片描述

编写Pipelines,处理获取的数据

编写pipelines.py文件

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter


class BaidustocksPipeline:
def process_item(self, item, spider):
return item

class BaidustocksInfoPipeline(object):
def open_spider(self, spider):
self.f = open('BaiduStockInfo.txt', 'w')

def close_spider(self, spider):
self.f.close()

def process_item(self, item, spider):
try:
line = str(dict(item)) + '\n'
self.f.write(line)
except:
pass
return item

配置ITEM_PIPELINES选项

编写settings.py文件 在其中寻找参数ITEM_PIPELINES,并修改如下参数。

在这里插入图片描述

执行整个框架

在cmd中:

scrapy crawl stocks

接下来等就完事儿啦=。= 在这里插入图片描述 在这里插入图片描述搞定收工!

· 7 分钟阅读
Allen Ma

最近进厂实习,互联网金融相关岗位,发现所学的有几分韵味。所以决定抽空列举几个相关案例,学而时习之。

案例(一)python预热

项目中的数据获取和处理大多采用的是python编程语言,所以我们首先来复习下一些常用函数与书写规则。

项目一:字典统计排序

字典d中存储了我国42所双一流高校及所在省份的对应关系,请以这个列表为数据变量,完善Python代码,统计各省份学校的数量。‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬

输出显示出数量最多的省份及数量。‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬

d = {"北京大学":"北京", "中国人民大学":"北京","清华大学":"北京",\ "北京航空航天大学":"北京","北京理工大学":"北京","中国农业大学":"北京",\ "北京师范大学":"北京","中央民族大学":"北京","南开大学":"天津",\ "天津大学":"天津","大连理工大学":"辽宁","吉林大学":"吉林",\ "哈尔滨工业大学":"黑龙江","复旦大学":"上海", "同济大学":"上海",\ "上海交通大学":"上海","华东师范大学":"上海", "南京大学":"江苏",\ "东南大学":"江苏","浙江大学":"浙江","中国科学技术大学":"安徽",\ "厦门大学":"福建","山东大学":"山东", "中国海洋大学":"山东",\ "武汉大学":"湖北","华中科技大学":"湖北", "中南大学":"湖南",\ "中山大学":"广东","华南理工大学":"广东", "四川大学":"四川",\ "电子科技大学":"四川","重庆大学":"重庆","西安交通大学":"陕西",\ "西北工业大学":"陕西","兰州大学":"甘肃", "国防科技大学":"湖南",\ "东北大学":"辽宁","郑州大学":"河南", "湖南大学":"湖南", "云南大学":"云南", \ "西北农林科技大学":"陕西", "新疆大学":"新疆"}

输出格式 ==省份:数量 (中文冒号)==

d = {"北京大学":"北京", "中国人民大学":"北京", "清华大学":"北京",
"北京航空航天大学":"北京", "北京理工大学":"北京", "中国农业大学":"北京",
"北京师范大学":"北京", "中央民族大学":"北京", "南开大学":"天津",
"天津大学":"天津", "大连理工大学":"辽宁", "吉林大学":"吉林",
"哈尔滨工业大学":"黑龙江", "复旦大学":"上海", "同济大学":"上海",
"上海交通大学":"上海","华东师范大学":"上海", "南京大学":"江苏",
"东南大学":"江苏", "浙江大学":"浙江", "中国科学技术大学":"安徽",
"厦门大学":"福建", "山东大学":"山东", "中国海洋大学":"山东",
"武汉大学":"湖北", "华中科技大学":"湖北", "中南大学":"湖南",
"中山大学":"广东", "华南理工大学":"广东", "四川大学":"四川",
"电子科技大学":"四川", "重庆大学":"重庆", "西安交通大学":"陕西",
"西北工业大学":"陕西", "兰州大学":"甘肃", "国防科技大学":"湖南",
"东北大学":"辽宁","郑州大学":"河南", "湖南大学":"湖南", "云南大学":"云南",
"西北农林科技大学":"陕西", "新疆大学":"新疆"}
counts = {}
for place in d.values():
counts[place] = counts.get(place, 0) + 1
items = list(counts.items())
items.sort(key=lambda x: x[1], reverse=True)
print(items[0][0]+':'+str(items[0][1]))

运行结果: pg1

项目二:计算手机销量年增长率

1.文件smartphone.txt存放着某些公司手机年销量数据,每行为每家公司若干年销量(百万),数据间的分隔符为制表符。

2.打开文件请注明文件编码格式:with open("smartPhone.txt",encoding="gbk") as f:

smartPhone.txt文件内容如下:

公司  2014年   2015年   2016年   2017年
Samsung 311 322.9 310.3 318.7
Apple 192.9 231.6 215.2 15.8
Huawei 73.6 104.8 139.1 153.1
OPPO 29.9 50.1 92.9 121.1
Vivo 19.5 40.5 74.3 100.7
ZTE 43.8 56.2 60.1 44.9
LG 59.2 59.7 55.1 55.9
Lenovo 70.1 74.1 50.7 49.7
Xiaomi 61.1 70.7 61.5 96.1

3.编写函数isBigGrowth(L,rate),形参L为一组含有数值型数据的列表(某公司各年份的销量),rate为年增长率,判断并返回是否年销量快速增长:若每年销量增长率都超过给定的rate,则为True,否则为False。

4.主程序读取smartphone.txt内的数据,将每行数据中的年销量转为数值型数据,利用函数isBigGrowth(L,rate)计算并屏幕输出各公司年销量是否快速增长的情况(本题设年销量增长率均超过30%为快速增长),各数据间以制表符相隔。

5.程序运行结果如下图所示: 手机公司 |是否快速增长? -------- | ----- Samsung |否 Apple |否 Huawei |否 OPPO |快速 Vivo |快速 ZTE |否 LG |否 Lenovo |否 Xiaomi |否

import os

def isBigGrowth(L,rate):
if float (L[2])>float(L[1])*(1+rate) and float(L[3])>float(L[2])*(1+rate) and float(L[4])>float(L[3])*(1+rate):
return "快速"
else:
return "否"

with open(r"文件路径\smartPhone.txt") as f:
line = f.read().strip()
linestr = line.split("\n") # 以换行符分隔
del linestr[0]
print("手机公司 是否快速增长?")
for s in linestr:
try:
L = s.split('\t')
print(L[0], end=" ")
print(isBigGrowth(L, 0.3))
except:
print('运行失败')

运行结果: 在这里插入图片描述

· 16 分钟阅读
Allen Ma

文章简介

一篇关于网址、URL、IP地址、域名、DNS、域名解析的白话长文。

编写形式:QA

背景知识

互联网上的所有数据都是存储在主机(服务器)上

互联网中的所有主机都拥有唯一的IP地址

互联网中任意两台主机通信都是通过IP地址来实现

了解上述内容之后,我们以两台主机最简单的通信方式——上网为例,为大家说明这个疑问是什么。

21世纪的每个人应该都熟悉网上冲浪(不知道还有没有人用这个词)的过程,我们上网的实质就是获取网址对应主机上的数据并在用户主机上进行展示(浏览器上),那么我们就该怀疑一个问题:

互联网中的任意两台主机通信是依靠IP地址进行的,而我们上网只是输入的网址,并不是IP地址,怎么就能找到对方主机并获取它的数据呢?

因此,势必存在某种机制,将网址解析成为了IP地址,再通过IP地址进行通信!这个机制也是贯穿本文所有技术知识的主线!

网址

网址是什么?

网址,也叫做域名,又称URL,是互联网用户用来标识主机的名字,该名字具有唯一性,层次性,字面意义可以表示主机的账号、功能、性质、所属的地区或组织,便于所有互联网用户记忆与使用!

URL,即Uniform Resource Locator,统一资源定位符,用于指明互联网主机的服务器及具体的网页位置,URL的构成策略与示例如下:

在这里插入图片描述

在这里插入图片描述

网址的出现解决了什么问题?

网址/域名/URL的出现解决了以下两个问题:

问题一:IP地址是互联网中所有主机的统一寻址方式,使用IP地址能够直接访问互联网上主机数据、资源,但由于IP地址只是一串数据,不具有实际意义,导致所有互联网用户记忆起来十分困难。

问题二:在Internet架构中,几乎所有的应用层软件都不是通过IP地址来访问互联网中的主机资源,而是要求用户输入具有一定意义的主机名字来访问对应主机的。

网址的结构组成

上面提到的主机名称,也就是网址/域名的命名遵循了一定规则,这个规则便是由互联网中的“名字管理机构”来制定的,即域名系统DNS。这里先介绍下网址的组成:

互联网中的某台主机域名由其所属各级域名及其自身名字共同组成(即由子域名构成),级别从左到右依增加,最右边为顶级域名,最左边为主机自己的名字,各级子域名使用“.”隔开,常见的格式如下:

www.ustc.edu.cn 主机名.机构名.网络名.顶级域名

DNS域名系统

DNS是什么?

DNS,英文全写为Domain Name System,中文意思为域名系统,是互联网中提供域名与IP地址互相映射的分布式数据库。

DNS发展史

1.ARPANE时代,约1969-1983,用host.txt记录计算机名与其IP地址。 2.1983年,域名系统诞生,DNS由此而来。 3.1985年,Symbolics公司注册首个.com域名。 4.1993年NetworkSolution(NSI)公司独家代理.COM、.ORG、.NET三个国际顶级域名注册权。 5.1994年开始NSI向每个域名收取100美元的注册费。 6.1997年3字母域名被注光。 7.1998年Interner域名的管理权由美国政府移交给民间机构。 8.2001年7个新顶级域名在ICANN大会上诞生。 9.2013年4字母.com域名被注光。

DNS解决了什么问题?

前文已经提到DNS域名系统是互联网中的主机域名管理系统,充当“管理员”的角色!DNS在诞生之前(ARPANET时期),互联网中的每台主机都是用一个文件来纪录所有的主机名及其IP地址,这个文件就是hosts.txt (现在是hosts文件,无后缀),所有主机都必须定期从相应站点来更新该文件,用于同步互联网中主机的新增、变更、消失。

可以想象,随着互联网中的主机数量增加,hosts文件必将越来越大,在维护更新方面的难度更是激增,主机名更是频繁发生冲突,为了解决这个问题,1983年DNS域名系统问世。

DNS域名层次结构

DNS是一个分层的树形结构,各层由域构成,域的意义如下:

域表示一个区域、一个范围

每个域可容纳大量主机

每个主机必有自己的域,却不一定有自己的域名地址

DNS标准规定,单个域名长度一般在63个字符以内,最长不超过255个字符

DNS标准规定,域名中的字符限26个字母(不分大小写),数字,连字符“-”(不能作为子 域名首字母与末尾字母)

域所在服务器称为域名服务器,主要用于将域名映射为IP地址(详见后文)

DNS的域名树由根域,顶级域,二级域及其子域构成,其结构图与示例如下:

在这里插入图片描述 下面逐一介绍各级域:

根域

由互联网网络信息中心(InterNIC)负责管理,用点“.”表示,无名称,是域名系统中的最高级别域,标准域名结尾应包含根域“.”,但实际使用中该根域都是省略的,所以大家常见的网址末尾并没有“.”。

顶级域(Top-Level Domains = TLD)

隶属于根域,是仅次于根域的下一级域,由国家顶级域(ccTLD)与通用顶级域(gTLD)共同组成。国家顶级域共有243个(即全球的国家与地区总数),而通用顶级域,也叫国际域名,其数量是随着因特网的发展在逐渐增加,理论会达到无穷多个。下表罗列出了常见的通用顶级域名:

在这里插入图片描述

二级域

正式给组织和个人注册使用的唯一名称,如亚马逊、IBM,微软的官方网址(头条不能带网址)中的字眼“amazon”“ibm”“microsoft”就是这些企业注册的二级域名。

二级域以下子域

在二级域中的组织机构可以根据需要来进一步划分子域,如销售部门用sale子域名,业务部门用business子域名等。

前文中已经提到域名的出现是为了解决用户记忆困难的问题,实际在互联网中并不能使用域名进行主机间的通信,而仍然需要使用IP地址进行数据交互,所以DNS系统在提供域名功能的同时更大的作用是能够高效的将域名解析映射到对应主机的IP地址。这就是即将为大家介绍的域名服务器的作用。

域名服务器

域名服务器构成了DNS中的分布式网络系统,其功能主要是为内外主机提供域名与IP地址的互相解析映射服务。域名服务器分布在互联网的各子网中,每个域名服务器负责管理连接到本子网的所有主机,并为其提供服务,服务内容为:

客户机应用程序将目标主机域名发送给其所属子网的域名服务器,域名服务器给该客户机返回对应的目标主机IP地址;若本子网中的域名服务器无法查询到目标主机域名的IP,则根据DNS的标准IP地址解析流程提供进一步的查询服务,该过程将在下文“域名解析过程”中详细介绍。

域名解析过程

通过域名获取对应IP地址的过程叫做域名解析,参与域名解析过程最重要的单元就是域名服务器,域名服务器的体系结构如下:

在这里插入图片描述

根域名服务器

是全球级别最高,最重要的域名服务器,全世界共有13台(IPv4根域名服务器,编号为A到M),1个主根服务器和9个辅根服务器在美国,欧洲2个辅根服务器,位于英国和瑞典,亚洲1个辅根服务器,位于日本。根域名服务器只纪录其下级顶级域名服务器的域名及其IP地址,当低级域名服务器遇到无法解析的域名时,首先会向根域名服务器求助。

顶级域名服务器

级别同顶级域,用于纪录注册在该顶级域名服务器上的所有二级域名并提供DNS查询服务。

权限域名服务器

为一个区域的主机提供DNS查询服务,如果查询结果为空,则通知发起请求的DNS用户应到哪个权限域名服务器进一步查询。

本地域名服务器

不在上图的域名服务器体系中,但在域名解析中扮演重要的角色。每主机发出的DNS域名查询请求首先都会发送到本地域名服务器。本地域名服务器可以设立在个人,大学,公司等各种范围内,又叫做首选DNS(很熟悉吧),就是我们计算机网络连接中的首选DNS: 在这里插入图片描述 在这里插入图片描述 上图以用户访问头条网站为例,简明扼要的为大家讲述了用户输入网址到获取IP地址的全过程,下面我们来详细解释该过程:

用户打开计算机,在浏览器中输入头条网址后计算机将向本地DNS服务器发起域名解析请求。本地DNS服务器通常由互联网服务提供商(ISP)提供,如三大运营商。

本地DNS服务器接收到用的DNS请求后,首先查询其自身缓存纪录中是否存在头条域名对应的IP地址,如果存在,则直接将该IP地址回传给用户计算机;否则,将进一步向根域名服务器发起求助。

由于根域名服务器只会纪录其下级的13个顶级域名服务器,而不会直接纪录域名与IP的映射关系,所以在接收到本地域名服务器的解析请求时,根域名服务器将告知本地服务器:“你所请求的域名由.com顶级域名服务器管理,其IP为xxx”。

本地DNS服务器进一步向.com顶级域名服务器发起域名解析请求,由于.com域名服务器也不会纪录域名与IP的映射关系,而是告知请求者去该域名所属的域服务器上查询,并给出其IP地址。

本地DNS服务器继续向域服务器发起头条域名解析请求,便会得到头条域名对应的IP地址,这时本地DNS服务器不仅会向用户计算机返回IP地址,同时在其自身缓存中增加头条域名与其IP的纪录,从而加快其他计算机获取头条域名对应IP的解析速度。

· 9 分钟阅读
Allen Ma

宏观经济数据

可利用Tushare的内建函数从Tushare平台获取多种国内宏观经济数据,如多个时期的货币供应量、存款准备金率、存贷款利率、国内生产总值、居民消费价格指数及工业品出厂价格指数等。

在这里插入图片描述

货币供应量

通过ts.get_money_supply()函数可获取我国最近30年来各时期的货币供应量数据:

import tushare as  ts
df = ts.get_money_supply()
df.head()
df.columns

在这里插入图片描述 返回值说明:

参数解释
month统计时间
m2货币和准货币(广义货币M2)(亿元)
m2_yoy货币和准货币(广义货币M2)同比增长(%)
m1货币(狭义货币M1)(亿元)
m1_yoy货币(狭义货币M1)同比增长(%)
m0流通中现金(M0)(亿元)
m0_yoy流通中现金(M0)同比增长(%)
cd活期存款(亿元)
cd_yoy活期存款同比增长(%)
qm准货币(亿元)
qm_yoy准货币同比增长(%)
ftd定期存款(亿元)
ftd_yoy定期存款同比增长(%)
sd储蓄存款(亿元)
sd_yoy储蓄存款同比增长(%)
rests其他存款(亿元)
rests_yoy其他存款同比增长(%)

存款利率和贷款利率

Tushare针对不同种类的利率提供了相应的接口函数,以便供开发者获取所需的利率数据。利用存款利率函数get_deposit_rate()和贷款利率函数get_loan_rate()可以分别获取我国自1989年以来中国人民银行发布的各期存款利率和贷款利率数据。

import tushare as  ts
df = ts. get_loan_rate()
df.head()

在这里插入图片描述 在这里插入图片描述

Shibor利率

上海银行间同业拆放利率(Shanghai Interbank Offered Rate,Shibor)是以位于上海市的全国银行间同业拆借中心为技术平台计算、发布并命名,由信用等级较高的银行组成报价团自主报出的人民币同业拆出利率计算确定的算术平均利率。

import tushare as  ts
pro = ts.pro_api('用户tushare token')
df=pro.shibor()
df.head()

在这里插入图片描述 其它的利率pro接口函数: (1)pro.shibor_quote():Shibor报价数据 (2)pro.shibor_lpr():LPR贷款基础利率 (3)pro.Libor():伦敦同业拆借利率 (4)pro.Hibor():香港银行同业拆借利率

股票行情数据

用户从Tushare平台可以获取上海证券交易所与深圳证券交易所全部上市公司的股票交易数据,也可以获取这两个市场的各类股票指数(如上证综合指数、深证成份指数、创业板指数、沪深300指数和中小板指数等)数据。 依次执行下列命令可以获取股票代码为600848的历史日线行情数据:

import  tushare  as  ts
df = ts.get_hist_data('600848', ktype = 'D')
df.head()

在这里插入图片描述在这里插入图片描述 返回值说明: 参数 | 解释 -------- | ----- date | 日期 open | 开盘价 high | 最高价 close | 收盘价 low | 最低价 volume | 成交量 price_change | 价格变动 p_change | 涨跌幅 ma5 | 5日均价 ma10 | 10日均价 ma20 | 20日均价 v_ma5 | 5日均量 v_ma10 | 10日均量 v_ma20 | 20日均量 turnover | 换手率

Tushare包提供一些pro接口函数返回股票历史行情数据。平台注册用户可以利用pro接口函数获取股票行情数据,但绝大部分pro接口函数要求用户具有一定的积分才可调用。 获取股票日线行情的pro接口函数的操作方法如下:

import tushare as  ts
pro = ts.pro_api()
df = pro.daily(ts_code = '600008.SH', start_date = '20000501', end_date = '20190808')
df.head()

在这里插入图片描述 用pro接口函数pro.daily()获取的行情数据与用get_hist_data()函数获取的行情数据在结构上有些差别。函数pro.daily()的返回数据采用默认索引,交易日期作为一个字段(列)数据项,而get_hist_data()函数的返回数据以交易日期作为索引。 鉴于不同接口函数返回数据的结构存在或多或少的差别,因此在设计处理这些数据的程序时必须根据返回数据的结构选择合适的处理方法,或者对返回的数据项进行必要的修改,以满足其他数据处理语句的格式要求。

在这里插入图片描述 Tushare还提供股票交易行情的实时数据,即当天正在交易的股票价格数据。例如,通过get_realtime_quotes()函数获取的股票交易实时分笔数据可以包括股票当前时刻报价列表和成交价格等信息、五档买入报价和五档卖出价格等数据项,共有30余项信息。操作过程如下:

import tushare as  ts
df = ts.get_realtime_quotes('300274')
df[['code','name','price','bid','ask','volume','amount','time']]

在这里插入图片描述 部分返回值说明: 参数 | 解释 -------- | ----- code | 股票代码 name | 股票名字 price | 当前价格 high | 今日最高价 low | 今日最低价 bid | 竞买价,即“买一”报价 ask | 竞卖价,即“卖一”报价 volume | 成交量 maybe you need do volume/100 amount,成交金额(元 CNY)

上市公司基本面数据

Tushare平台提供的上市公司基本面数据包括财务状况、盈利状况、市场占有率、经营管理体制、人才构成等各个方面的数据。除股票价格行情数据外,金融分析人员通常需要通过上市公司的基本面数据了解公司的投资价值。 Tushare提供上市公司基本面数据的接口函数如表所示。 在这里插入图片描述

股票指数数据

股票指数是由证券交易所或金融服务机构编制的反映某一组(类)股票价格变动的一种股票综合价格数值。

证券交易所及一些金融服务机构已经编制并公开发布了数十个股票价格指数,股票投资者也习惯以股票指数作为考察股票市场价格变动的观察指标。

运用pro.index_basic()函数可获取上交所发布的各项股票指数。

import  tushare  as  ts
pro = ts.pro_api('用户tushare token')
df = pro.index_basic(market = 'SSE')
df.head()

在这里插入图片描述 下面两表列出的Tushare平台pro版接口函数index_basic()的输入参数和输出参数信息所示。

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

· 6 分钟阅读
Allen Ma

股票基本面统计

使用get_stock_basics()函数一次性下载所有股票基本面数据。这对观察股票的整体市场情况很有帮助。

import  tushare  as  ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

stock = ts.get_stock_basics() # 下载股票基本面数据
stock.to_excel('stock.xlsx') # 保存为电子表格
stock.shape # Out: (3678, 22)

在这里插入图片描述在这里插入图片描述 数据集规模为3823x22,每行是一支股票的基本数据。字段详情请查看Tushare的网站。数据集字段详情查看http://tushare.org 网站。本节用到的数据列有:code,股票代码;name,名称;industry,所属行业;area,地区;pe,市盈率;totals,总股本(亿元人民币);esp,每股收益;timeToMarket,上市日期。

下面从电子表格文件中读取数据,注意股票代码code列的处理细节。Pandas读取数据时,总是试图将数据自动转换为数值类型。深市类似'002522'的股票代码读入后,将丢失前导字符“00”,变为整数2522,因此读取时特意指定code字段为字符串。

df = pd.read_excel('stock.xlsx', dtype={'code': 'str'})   # code字符串类型
df.set_index('code', inplace=True) # 将code设为索引列
df.loc['002522'] # 显示某支股票基本面

在这里插入图片描述

len(df.industry.unique())   # 显示行业数

在这里插入图片描述

len(df.area.unique())  # 显示地区数(即股票的归属省份)

在这里插入图片描述

# 按地区统计上市公司数量,体现地区经济实力
df.groupby('area').size().sort_values(ascending=False)

在这里插入图片描述 由上面的统计结果可见,经济越发达、越有活力的地区,上市公司的数量越多。读者还可以按行业进行类似的统计。数据框中的timeToMarket字段代表上市日期,其数据是格式形如“20190315”的整数类型。我们可以提取出其中的年份以统计每年的股票发行数量。

year = df.timeToMarket.astype('str').str[:4]  # 转为字符串,提取前4位的年份
yearnum = df.groupby(year).size() # 按年份统计,得到每年股票发行量
yearnum

在这里插入图片描述

plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文黑体字体
# 下面的False修正坐标轴上负号'-'显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
# 数据集中有几支股票没有发行年份(年份为0), 作图时排除0年份
yearnum[yearnum.index!='0'].plot(fontsize=14, title='年IPO数量')

在这里插入图片描述从图中可见IPO发行年份的几个高点和国内股票市场的几次牛市时间对应,熊市时发行数量跌入低谷。下面计算市场的平均市盈率pe,这是衡量股票市场估值的重要参数。

df.pe.mean()            # 简单的算术平均pe

在这里插入图片描述 观察数据集发现,数据集中亏损股票的pe为0,因此考虑剔除亏损股票。

df[df.pe > 0].pe.mean()     # 剔除亏损股票后计算pe均值

在这里插入图片描述 上面的pe是简单的算术平均,以市值为权重的加权pe可能更能准确地反映市场状况。由于下载的数据集中没有总市值和股票单价,因此只能根据现有的字段推算总市值。由某些列的值计算新的列值也是数据处理中常有的情况。这里推算总市值的依据如下: 股票单价 = 4esp(每股收益)pe(市盈率) 总市值 = 股票单价*totals总股本(亿元人民币) 数据集中每股收益esp是单个季度的收益,因此全年收益要乘以4。

df['tvalue'] = 4 * df.esp * df.pe * df.totals   # 计算总市值,增加新列tvalue
np.sum(df.pe * df.tvalue) / df.tvalue.sum() # 计算以市值为权重的加权pe

在这里插入图片描述 上面的计算结果反映了某次季报后的市场加权pe情况,结果和市场真实值相比有差异。这是因为股票的每个季度收益不同,因而不能简单按“4*单季收益”来计算全年收益。

我国股票市场现分为沪市(股票代码60开头)、深圳主板(股票代码00开头)、创业板(股票代码30开头)及最新上市的科创板(股票代码68开头)。如下代码可计算不同板块的pe值和股票数。

df['board'] = df.index.str[:2]     # 取code的前2个字符,新增board列
# 按板块类型统计pe均值,计数
df.groupby('board').pe.agg([('pe均值', 'mean'), ('股票数', 'count')])

在这里插入图片描述

· 6 分钟阅读
Allen Ma

绘制股票k线图

不同种类财经数据的结构与变化特征是有差别的,适合描述不同种类数据特征的图表形式自然也会不同。线图和点图是金融分析者最常用的二维图,因为二维线图与点图比较容易展示金融数据的变化特征,并且绘制方法也较简单。本节以绘制股票k线图(也称蜡烛图)为例介绍Python语言实现时间序列数据可视化的基本方法。

在Python运行环境下利用Tushare平台数据绘制股票k线图的过程主要包含如下三个步骤:

第1步:确定数据来源。本节选择从Tushare平台获取股票行情数据,并利用Tushare包的内建接口函数获取股票行情数据,所以首先要使用命令import tushare导入Tushare包。

第2步:确定可视化的形式和实现工具。本节选择金融学图表包mpl_finance作为绘制股票价格k线图的工具,所以需要使用命令“from mpl_finance import candlestick_ochl”导入mpl_finance包中绘制k线图的子模块candlestick_ochl。 mpl_finance包是从Matplotlib中独立出来的图形包(执行“pip install mpl_finance”命令完成包的安装),通常用于绘制股票价格k线图及线图。由于Tushare包提供的pro接口函数与普通接口函数返回的数据结构存在差异,所以在调用绘图函数时需要确保数据格式的匹配。本节的程序中利用pro接口的 pro.daily()函数获取股票日线数据,并根据mpl_finance包的candlestick_ochl()函数的参数格式要求对行情数据结构进行适当的调整。此外,输出图表中绘制的k线数量不宜太多,因为k线数量太多势必导致k线之间距离太小而使得k线图不够清晰。

第3步:确定绘制图表的输出工具。本节选择图表绘制包Matplotlib作为k线图的输出工具,因为Matplotlib包提供了丰富的图表输出功能,可以比较容易地对图表的结构布局、颜色及坐标轴格式等诸多方面进行设置,使得图表更美观,也更容易理解。所以在程序中需要导入模块Matplotlib,命令为“import matplotlib”。

import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import ticker
from matplotlib.pylab import date2num
#from mpl_finance import candlestick_ochl #需要另外安装mpl_finance包
from mplfinance.original_flavor import candlestick_ochl #需要另外安装mpl_finance包
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签

#具有足够权限的用户是用pro接口获取数据
pro = ts.pro_api()
code = '600004.SH'
df = pro.daily(ts_code=code, start_date='20191201')
df.shape
#stock_daily = pro.daily(ts_code=code, start_date='20181201')
#stock_daily.to_excel('stock_daily.xlsx') # 保存为电子表格

#不具有足够权限使用pro接口获取数据的用户执行下面代码,直接从xlxs文件中获取数据
df = pd.read_excel('stock_daily.xlsx', dtype={'code': 'str','trade_date': 'str'})
df.drop(df.columns[0], axis=1, inplace=True)
df.shape

df2 = df.query('trade_date >= "20171001"').reset_index() #选取2017年10月1日后的数据
df2 = df2.sort_values(by='trade_date', ascending=True) # 原始数据按照日期降序排列
df2['dates'] = np.arange(0, len(df2)) # len(df2)指记录数
fig, ax = plt.subplots(figsize=(20, 9))
fig.subplots_adjust(bottom=0.2) # 控制子图
###candlestick_ochl()函数的参数
# ax 绘图Axes的实例
# quotes 序列(时间,开盘价,收盘价,最高价,最低价) 时间是float类型,date必须转换为float
# width 图像中红绿矩形的宽度,代表天数
# colorup 收盘价格大于开盘价格时的颜色
# colordown 低于开盘价格时矩形的颜色
# alpha 矩形的颜色的透明度
candlestick_ochl(ax, quotes=df2[['dates', 'open', 'close', 'high', 'low']].values,
width=0.55, colorup='r', colordown='g', alpha=0.95)
date_tickers = df2['trade_date'].values
def format_date(x, pos):
if (x < 0) or (x > len(date_tickers)-1):
return ''
return date_tickers[int(x)]
ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) #按一定规则选取并在水平轴上显示时间刻度
plt.xticks(rotation=30) # 设置日期刻度旋转的角度
ax.set_ylabel('交易价格')
plt.title(code)
plt.grid(True) # 添加网格,可有可无,只是让图像好看一些
plt.xlabel('交易日期')
plt.show()


在这里插入图片描述