数据分析—numpy

1
2
import pandas as pd
import numpy as np

创建普通数组

1
2
a = np.array([1,2,3])
b = np.array([[1,2,3],[4,5,6],[7,8,9]])
1
b[1,1] = 10
1
2
3
4
print(a.shape)
print(b.shape)
print(a.dtype)
print(b)
(3,)
(3, 3)
int64
[[1 2 3]
 [4 5 6]
 [7 8 9]]

创建结构数组

1
2
3
4
5
6
7
personalType = np.dtype({
'names':['name','age','chinese','math','english'],
'formats':['S25','i','i','i','f']
})
students = np.array([("huzai",22,99,99,99.5),("huzai",22,99,99,99.5)],dtype=personalType)
age = students[:]['age']
print(np.mean(age))
22.0
1
print(students)
[(b'huzai', 22, 99, 99, 99.5) (b'huzai', 22, 99, 99, 99.5)]

创建连续数组

1
2
x1 = np.arange(1,11,2) #步长为2,从1开始的等差数组(不包括终值)
x2 = np.linspace(1,9,5) #将1-9分成5块,结果如上
1
2
print(x1)
print(x2)
[1 3 5 7 9]
[1. 3. 5. 7. 9.]

数组间的算数运算

1
2
3
4
print(np.add(x1,x2))
print(np.subtract(x1,x2))
print(np.multiply(x1,x2))
print(np.divide(x1,x2))
[ 2.  6. 10. 14. 18.]
[0. 0. 0. 0. 0.]
[ 1.  9. 25. 49. 81.]
[1. 1. 1. 1. 1.]

统计函数

数组中的最值 np.amin() amax()

1
2
3
4
a = np.array([[1,3,7],[2,5,8],[6,4,9]])
print(np.amin(a))
print(np.amin(a,0)) #每一列的最小值
print(np.amin(a,1)) #每行的最小值
1
[1 3 7]
[1 2 4]

统计最大值与最小值之差 ptp()

1
2
3
print(np.ptp(a))
print(np.ptp(a,0)) #每列最大值与最小值的差
print(np.ptp(a,1)) #每行最大值与最小值的差
8
[5 2 2]
[6 6 5]

统计数组的百分位数 percentile(a, p, axis) a:数组名 p 代表百分比 axis代表是行还是列

1
2
3
print(np.percentile(a,50))
print(np.percentile(a,50,0))
print(np.percentile(a,50,1))
5.0
[2. 4. 8.]
[3. 5. 6.]

统计数组中的中位数以及平均数 median() mean()

1
2
3
print(np.median(a))
print(np.median(a,0))
print(np.median(a,1))
5.0
[2. 4. 8.]
[3. 5. 6.]

数组中的加权平均值 average(a,weights)

1
2
3
4
b = np.array([1,2,3,4])
wts = np.array([1,2,3,4])
print(np.average(b))
print(np.average(b,weights=wts))
2.5
3.0

统计数组中的标准差(std())与方差(var())

1
2
print(np.std(b))
print(np.var(b))
1.118033988749895
1.25

Numpy排序

1
2
3
print(a)
print(np.sort(a))
print(np.sort(a,0))
[[1 3 7]
 [2 5 8]
 [6 4 9]]
[[1 3 7]
 [2 5 8]
 [4 6 9]]
[[1 3 7]
 [2 4 8]
 [6 5 9]]

作业题

1
2
3
4
5
6
st_type = np.dtype({
'names':['name','chinese','english','math'],
'formats':['S25','i','i','i']
})
grades = np.array([('zhangfei',66,65,30),('guanyu',95,85,98),('zhaoyun',93,92,96),('huangzhong',90,88,77),
('dianwei',80,90,90)],dtype=st_type)
1
print(grades)
[(b'zhangfei', 66, 65, 30) (b'guanyu', 95, 85, 98)
 (b'zhaoyun', 93, 92, 96) (b'huangzhong', 90, 88, 77)
 (b'dianwei', 80, 90, 90)]
1
2
3
4
chinese = grades[:]['chinese'] 
english = grades[:]['english']
math = grades[:]['math']
total = np.add(chinese,english,math)
1
print(total)
[131 180 185 178 170]
1
c_a,e_a,m_a = np.average(chinese),np.average(english),np.average(math)
1
print(c_a)
84.8
1
2


遇到的问题

  • 先上一张图,看一下问题在哪
    1.png

从图上我们可以看到,虽然小说是每天发两次给我,但是有时候会漏掉一章,有时候又会重复发一章,这都是小说作者不按时更新惹的祸啊!!!既然小说作者的习惯改变不了,那就完善自我吧!

新的思路,加一个“缓存”

缓存是什么意思呢?

  • 本地建一个名为origin.txt的文本文件,每次爬取完成后与origin.txt里面的内容对比一下。
  • 如果一样则不发送。
  • 如果不一样就发送,并且将最新的内容保存到origin.txt文件中,作为下一次的对照。

演示效果

  • 再origin.txt里写入test,然后启动
    2.png
    我们可以看到,origin文件已被重新写入,并且新的文本已经发送到邮箱
  • 再次启动,也就是还没跟新的情况
    3
    我们看到,提示消息,这里不会跟新origin,也不会发送邮件

还遗留的问题

  • 如果作者一下爆发怎么办(一分钟更新十章!)
    思考一下,其实原理差不多,缓存大小不同罢了!有兴趣的可以尝试一下!

    项目源码已发布在github

    https://github.com/huzai9527/fictionSend

指针究竟是什么

  • 指针是一类特殊的变量,他保存的不是一般数据的值,而是程序中另一对象在内存中的地址
    我们先通过一个小程序看一看指针如何工作
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <iostream>
    using namespace std;
    int main(){
    int n = 123,m = 456;
    int *p = &n;
    cout<<"&n:"<<&n<<endl;
    cout<<"&p:"<<&p<<endl;
    cout<<" p:"<<p<<endl;
    cout<<"*p:"<<*p<<endl;
    return 0;
    }

1
从运行结果可以看出下面几点:

  • p本身是有一个地址的且地址为 &p
  • p的值是另一个变量n的地址 &n
  • *p所表示的意思是地址为 p 的内存中所存的值 n
  • 即本段程序中共涉及到2个地址,一个是 n 的地址,一个是 p 的地址,我们用一张图来表示他们的关系
    2

    指针的初始化

  • 被具有相同类型的对象初始化

    1
    2
    int i = 10;
    int *p = &i;
  • 由另一个同一类型的指针初始化,这时两个指针指向同一地址空间

    1
    int *p1 = p;
  • 通过直接分配内存地址得到初值

    1
    int *p2 = new int;
  • 指针也可以没有类型,通用指针的定义,这样的指针可以指向任一对象

    1
    void *p3

指针的运算符

定义指针的目的事通过指针变量间接的访问变量

  • *:取指针值运算符。通过指针所指内存单元的地址间接的访问对应的存储单元。若指针变量p指向变量a,则 *p的运算结果为变量a的值
  • &:取地址运算符。返回变量对应的存储单元地址,若a为int变量,p为int型指针变量,则 p = &a表示将a的存储单元地址赋给p。
    用一个程序验证一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <iostream>
    using namespace std;
    int main(){
    int a = 100;
    int *p,*p1,*q;
    p = &a;
    p1 = p;
    q = NULL;
    cout<<"a="<<a<<","<<"*p="<<*p<<","<<"p="<<p<<endl;
    *p1 = 200;
    cout<<"a="<<a<<","<<"*p="<<*p<<","<<"p="<<p<<endl;
    cout<<"*p1="<<*p1<<","<<"p1="<<p1<<endl;
    }
  • 运行结果
    3.png

    指针与数组的关系

  • 数组名和指针在引用数组元素和取他们的地址方面可以相互转换,但两者有一个重要的不同点
  • 数组是在定义时就分配好内存空间的,因此数组名是一个地址常量,在程序中不能将数组名作为变量为其赋值,而指针是一个变量,可以多次赋值
    我们通过一个程序看一下他们的关系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <iostream>
    using namespace std;
    int main(){
    int a[10]={1,2,3,4,5,6,7,8,9,10};
    int *pa = a;
    int i = 3;
    cout<<"a[i] :"<<a[i]<<endl;
    cout<<"*(pa+i):"<<*(pa+i)<<endl;
    cout<<"*(a+i) :"<<*(a+i)<<endl;
    cout<<"&a[i] :"<<&a[i]<<endl;
    cout<<"a+i :"<<a+i<<endl;
    cout<<"pa+i :"<<pa+i<<endl;

    }
  • 运行结果
    4

    易重要的和易混淆的概念

  • 为什么要对指针初始化?
    定义了指针变量后,系统会为其分配一个内存空间,若没有赋值则此内存区域的内容是随机的,也就是指针随机指向一个内存单元。你想想如果你对一个随机的内存空间进行写操作,会怎样!
  • 指针的运算
    指针 + 整数 = 指针
    指针 - 指针 = 整数 //同类行的指针相减表示两个基类型变量的个数
    指针 + 指针 = ???? //不可以
  • new、 new[]、 delete、 delete[]有什么区别

    1
    2
    3
    4
    int *p = new int(3) // 为p分配了一个整形变量的存储区域并初始化为3
    int *p1 = new int[20] // 分配20个整形变量的区域给p1
    delete p //释放有new申请的空间
    delete[] p1 //释放由new[]申请的空间
  • c++程序中动态分配的内存不会被自动释放

  • 指针函数和函数指针含义相同吗?
    完全不同!
    指针函数:若一个函数返回的是一个地址,则称该函数为指针函数。格式是 数据类型 函数名(参数列表)
    函数指针:指针变量指向一个函数的入口地址,格式为 数据类型 (
    函数指针变量)(参数列表)
    函数指针的用法:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include <iostream>
    using namespace std;
    int cul(int (*pf)(int,int), int x, int y){
    return pf(x,y);
    }
    int add(int x,int y){
    return x+y;
    }
    int sub(int x,int y){
    return x-y;
    }
    int main(){
    int a=10,b=20;
    cout<<a<<"+"<<b<<"="<<cul(add,a,b)<<endl;
    cout<<a<<"-"<<b<<"="<<cul(sub,a,b);
    }

5

  • 常量指针、指针常量、指向常量的指针常量有什么区别
    常量指针:表示指针指向的是一个常量,格式:const 类型 指针变量 或 类型 const 指针变量
    1
    2
    3
    4
    int i;
    const int *p = &i;
    *p = 10; //错误
    i = 10; //正确

指针常量:表示所定义的指针是一个常量,只能在定义的时候初始化

1
2
3
int i,j;
int * const p = &i;
p = &j;//错误

指向常量的指针常量:格式为 const 类型 * const 指针常量

1
2
3
4
5
int i,j;
const int * const p = &i;
*p = 10;//错误
p = &j;//错误
i = 10;//正确

c++

用scrapy爬取可用的代理

分析免费代理网站的结构

  • 我爬取了三个字段:IPporttype
    TIM图片20181118171534.jpg

    分析要爬取的数据,编写items.py

  • 因此在items.py中,建立相应的字段
    1
    2
    3
    4
    5
    6
    7
    import scrapy
    class IproxyItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    ip = scrapy.Field()
    type = scrapy.Field()
    port = scrapy.Field()

爬取所有的免费ip

  • 在spider目录下,创建IpSpider.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import scrapy
    import Iproxy.items
    class IpSpider(scrapy.Spider):
    name = 'IpSpider'
    allowed_domains = ['xicidaili.com']
    start_urls = ['http://www.xicidaili.com/']

    def parse(self, response):
    item = Iproxy.items.IproxyItem()
    item['ip'] = response.css('tr td:nth-child(2)::text').extract()
    item['port'] = response.css('tr td:nth-child(3)::text').extract()
    item['type'] = response.css('tr td:nth-child(6) ::text').extract()
    yield item

检测是否可用,如果可用则存入数据库

  • 因为是免费的ip,所以我们有必要检测一下他是否可用,对于可用的就存入数据库,反之则丢弃
  • 检测处理数据在pipeline.py中编写
  • 检测原理,通过代理访问百度,如果能够访问,则说明可用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    # -*- coding: utf-8 -*-

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

    import pymysql
    import requests

    class IproxyPipeline(object):
    def process_item(self, item, spider):
    print('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
    db = pymysql.connect("localhost", "root", "168168", "spider")
    cursor = db.cursor()
    for i in range(1, len(item['ip'])):
    ip = item['ip'][i] + ':' + item['port'][i]
    try:
    if self.proxyIpCheck(ip) is False:
    print('此ip:'+ip+"不能用")
    continue
    else:
    print('此ip:'+ip+'可用,存入数据库!')
    sql = 'insert into proxyIp value ("%s")' % (ip)
    cursor.execute(sql)
    db.commit()
    except:
    db.rollback()
    db.close()
    return item

    def proxyIpCheck(self, ip):
    proxies = {'http': 'http://' + ip, 'https': 'https://' + ip}
    try:
    r = requests.get('https://www.baidu.com/', proxies=proxies, timeout=1)
    if (r.status_code == 200):
    return True
    else:
    return False
    except:
    return False

运行情况

  • 可以看出还是有好多ip不能用的
    TIM图片20181118172712.png
  • 可用的存在数据库
    TIM图片20181118172841.jpg

数据获取—Spider()

找目标网站,该网站是你看小说的网站,分析该网站的结构方便你对内容的抓取

1.png
这里我获取最新章节的时间、标题以及标题的连接
2.png
这里获取内容

编写spider方法,确定他的返回值,这里我返回的是一个list,包括更新的时间、标题、内容

  • 方法中需要导入的包 requests bs4 re
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    def spider():
    list = []
    response = requests.get('https://www.xbiquge6.com/13_13134/')
    response.encoding = ('utf-8')
    html = response.text
    html = BeautifulSoup(html, 'html.parser')
    time = html.select('div#info p:nth-of-type(3)').__getitem__(0).text[5:]
    title = html.select('div#info p:nth-of-type(4) a[href]').__getitem__(0).text
    href = html.select('div#info p:nth-of-type(4) a[href]').__getitem__(0)
    # print(title)
    pattern = re.compile(r'href="(.+?)"')
    href = re.findall(pattern, href.__str__()).__getitem__(0)
    href = "https://www.xbiquge6.com" + href
    response = requests.get(href)
    response.encoding = ('utf-8')
    html = BeautifulSoup(response.text, 'html.parser')
    content = html.select('div#content')
    # print(content)
    list.append(title)
    list.append(content)
    list.append(time)
    return list

邮件发送—smtp()

首先先在你的邮箱中设置打开smtp服务

比如我的QQ邮箱,先进入邮箱->点击设置->点击账户->下滑找到smtp服务->点击开启服务->生成授权码(就是你在smtp方法中用到的password)
![PCO_6AO93%@2W$B}GFGHI0 (1).png

编写smtp方法,向我的邮箱发送小说,确定返回值是bool类型,成功为True,失败为False

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def mail():
list = spider();
ret = True
try:
mail_msg = list.__getitem__(1).__str__()
msg = MIMEText(mail_msg, 'html', 'utf-8')
msg['From'] = formataddr(['huzai', my_sender])
msg['To'] = formataddr(['huzai', receiver])
msg['Subject'] = list.__getitem__(0)
server = smtplib.SMTP_SSL('smtp.qq.com', 465)
server.login(my_sender, my_pwd)
server.sendmail(my_sender, [receiver], msg.as_string())
server.quit()
except Exception:
ret = False
return ret

上传脚本到服务器

使用xftp将写好的smtp.py上传到你的云服务器上

3.png
直接拖进去就行

这里注意保证你的服务器上的python版本和你本机一致,且需要的包已经安装

  • 如果你的服务器上的版本是2.*的可以运行下面代码安装python3
    1
    2
    3
    sudo apt-get remove python
    sudo apt-get install python3
    sudo apt autoremove

用xshell进入服务器试着运行

TIM图片20181117155505.png

在服务器端设置定时执行

确保你安装了crontab(ubuntu默认安装)

cron命名解析:执行的时间 + 执行的用户 + 执行的命令
4.png

查看原有的cron

1
cat /etc/crontab

TIM图片20181117155728.png

编辑你的程序

1
sudo nano /etc/crontab

编写你的命令,每天14:58给我发送邮件,这里根据你看的小说的更新时间设置,一天几更在大约什么时间等等

1
58 14 * * * root python3 smtp.py

编辑好了再次查看cron是否已经写入,我这里已经写入
TIM图片20181117160221.png
重启crontab服务

1
service cron restart

静静的等待14:58的到来,查看邮箱

  • 邮件收到了最新更新的哦
    TIM图片20181117160515.png

1.创建的项目名默认为 用户名.github.io,创建时点击生成readme文件,方便后面添加说明

2.在本地创建一个文件夹,我是在E盘创建的blog,推荐用vscode作为编辑器,在编辑器里面打开文件夹,打开Terminer

使用vscode打开文件夹

3.使用hexo初始化文件夹,这一步会产生很多的hexo配置文件,我们先不管,先跑起来

hexo初始化文件夹

4.运行hexo server打开服务,看看本地能不能显示

hexo server
运行后访问url,如果看到如图就成功了
运行效果

5.配置文件中填写git的配置信息,按照如下格式填写

配置信息

6.打开文件夹,右键git bash here

git bash here

7.输入cd ~/.ssh,进入ssh文件夹

ssh

8.配置git中的用户名和邮箱

配置用户名

9.生成ssh密钥

生成密钥

10.在github的项目中加入密钥

添加密钥

11.测试密钥链接是否成功

测试

12.测试成功后再再编辑器中运行

hexo clean
hexo g
hexo d

4.png这样就算上传成功

13.访问你的博客,看到之前再本地运行的界面,就行了