来到大学之后,我开始用记账APP来记录我的各种收入和支出,开始用的APP是“口袋记账”,但是我经常遇到在食堂吃完饭忘记自己花了多少钱然后没有及时记帐的情况,学校的一卡通消费查询系统并不是实时统计的,似乎有一两天的延迟,加之碰上期末考试,我也没心思去理那么多了,时间长了遗留下来没记的支出越来越多,所以我打算集中一个时间用Excel来统计一下再把数据导入进去。后来我发现,这破玩意儿居然不支持数据导入?!这么基本的功能都没有,是想圈住用户投资他们的理财产品?怒弃之。换了据说很专业并且支持数据导入的“随手记”。

学校的一卡通消费查询系统不支持数据导出,要我一页页地把数据复制到Excel上?这种重复无聊的事情不应该是靠擅长做这些事情的计算机去解决的吗?所以我开始打算写个脚本一键抓取我的一卡通消费记录。<!--more-->
10.png

首先打开消费记录查询的网页,掏出开发者工具,观察这个网页,找到我们的目标,是一个table标签。
11.png

接着寻找这个标签是怎么生成的,是服务器后端直接生成出来的网页,还是前端ajax访问后端拿到数据再渲染出来的呢?点开Network标签刷新网页,发现网页并没有出现异步的请求,每一页都是一个新的网页,所以是前者的情况。而且每一页的url都是 http://app.scnu.edu.cn/ecard/consump.html?page=[页码] ,所以我只要让程序访问这个url并且解析其中的html,得到表格内部的数据,再通过某种方式收集起来就能完成目标了。

要将结果导入到Excel之中,这里用到了一种简单方便的表格文件格式————CSV,本质上 csv 的表格文件只是一种文本文件,它用逗号等分隔符分隔表格的字段,表格中每一行的数据用换行符分隔(在Excel里面换行符是"rn")

字段1,字段2,字段3,字段4
A,B,C,D
1,2,3,4

就是这么简洁明了!对于任意的程序,只需要简单的字符串拼接即可生成一个csv格式的表格。

经过我的测试,我这一个学期以来的消费记录在这个网页上只有50多页,所以爬虫需要爬取的数据量很小,处理起来是完全没有压力的,直接一次性得到所有的结果之后保存文件就行了。

至于爬虫程序的语言选择,我也没什么好说的,目前我也就对PHP比较熟悉一些,所以接下来的程序我也是用PHP完成的。

首先确定我应该怎么模拟登录这个系统,这里我们应该要知道,HTTP是一种无状态的协议,所以服务器要确定当前请求的用户是谁的话,就要通过HTTP请求的Cookie中保存的信息来确定。所以我们如果要让服务器知道爬虫发出的HTTP请求的用户是我的话,应该让爬虫发出的HTTP请求带上这个cookie,在这里我们可以把这个cookie从chrome复制出来,把它的值保存在某个变量之中备用。

查看浏览器访问这个页面的header,发现cookie只有JSESSIONID。

12.png

接下来写一个循环,把每一页抓取的结果添加到保存结果的字符串之中,当找不到数据时则跳出循环,保存结果,程序结束。

提取数据时我用了 simple_html_dom ,一个简单方便的解析html中的DOM结构的库。

最后将字符串中的内容保存到 result.csv 中。

代码如下:(GitHub地址: scnu_ecard_spider

<?php
/**
 * Created by PhpStorm.
 * User: qing
 * Date: 17-2-12
 * Time: 下午1:59
 */
require_once "simple_html_dom.php";

$cookie = "JSESSIONID=C73FF91A6FF439C073EC664E532C67E6";
$result = "消费时间,消费金额,卡内余额,消费地点\r\n";

$page = 1;

while (true){
    echo "Fetching page $page...\n";
    $html = get_url("http://app.scnu.edu.cn/ecard/consump.html?page=$page", $cookie);
    //echo $html;exit();
    if (!$html)
        exit("Network Error!!");
    if (strpos($html, "暂无数据") !== false)
        break;
    $dom = new simple_html_dom();
    $dom->load($html);
    $trs = $dom->find("table", 0)->find("tr");
    foreach ($trs as $tr){
        $arr = [];
        $tds = $tr->find("td");
        //忽略表头
        if (!$tds)
            continue;
        foreach ($tds as $td){
            //过滤结果中的标签
            $arr[] = strip_tags($td->innertext);
        }
        $result .= implode(",", $arr) . "\r\n";
    }
    $page++;
}

file_put_contents("result.csv", $result);

echo "Finished\n";

function get_url($url, $cookie=''){
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('User-Agent: Mozilla/5.0 (Linux; U; Android 4.1.2; zh-cn; MB526 Build/JZO54K) AppleWebKit/530.17 (KHTML, like Gecko) FlyFlow/2.4 Version/4.0 Mobile Safari/530.17 baidubrowser/042_1.8.4.2_diordna_458_084/alorotoM_61_2.1.4_625BM/1200a/39668C8F77034455D4DED02169F3F7C7%7C132773740707453/1','Referer: http://app.scnu.edu.cn/ecard/consump.html'));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_COOKIE, $cookie);
    $result = curl_exec($ch);
    $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE);
    if ($httpCode != 200) return false;
    curl_close($ch);
    return $result;
}

运行结果:

13.png

14.png

实践证明,cli模式下运行的PHP还是很给力的^_^



阅读全文 »

给笔记本装好Ubuntu之后,我按照 http://jingyan.baidu.com/article/335530da98061b19cb41c31d.html 的教程安装了Chrome,结果遇到了一些大坑:

  1. 将Chrome设置为默认浏览器之后,无论点击什么链接都只是打开了一个空白的新标签页
  2. 启动器的图标右键点开之后只有 “新标签页 - Google Chrome” 一个选项,没有新建窗口或者是新建隐身窗口的选项,点击启动器上的图标切换窗口也很有问题

一开始我通过 这篇帖子 解决了第一个问题,但第二个问题仍然百思不得其解。。。

后来我通过Ubuntu官网中 关于Unity启动器的文档 了解到,Unity的启动器显示的程序是由 /usr/share/applications/ 和 ~/.local/share/applications/ 目录里面的 .desktop 的文件来决定的,并且, ~/.local/share/applications/ 目录里的配置优先读取。

问题就出在那个百度经验的最后一步:

最后,如果一切顺利,在终端中执行以下命令:

    /usr/bin/google-chrome-stable

将会启动谷歌 Chrome 浏览器,它的图标将会出现在屏幕左侧的 Launcher 上,在图标上右键——“锁定到启动器”,以后就可以简单地单击启动了。

使用这个命令启动Chrome并且把它锁定启动器之后,程序在 ~/.local/share/applications/ 里面创建了 google-chrome.desktop 文件。这个文件仅仅只有启动 /usr/bin/google-chrome-stable 的选项。

当Chrome成为了默认浏览器,其它程序调用Chrome打开链接的时候,那个代表将要打开的链接的参数并没有没有传到 /usr/bin/google-chrome-stable 程序上,因此点击链接后打开的是一个空白的Chrome窗口。

发现了问题所在,我直接删除 ~/.local/share/applications/google-chrome.desktop ,这时候启动器上的图标消失了,重新在搜索框找到Chrome图标拖到启动器,终于恢复了正常。

所以,要添加Chrome浏览器到启动器,只需像安装其他程序一样,装完后直接在搜索那里找到对应的程序拖到侧栏即可。

不知道又会有多少人继续被那教程坑呢╮(╯_╰)╭

之前我用 lnmp.org 的一键安装包来配置 web 服务器,一直懒得去动,对 nginx 的配置也是一知半解。买了新的 vps 之后需要重新配置服务器环境,趁这个机会让我手动一个个安装它们并且熟悉熟悉吧。

部署vps时候我选了Ubuntu 16.04系统,所以以下操作均基于这个系统进行。

由于当时我是用root账户登录的,所以代码前面没有sudo,如果在Ubuntu桌面版安装的话记得每条命令之前加上sudo

更新软件列表并升级各种软件

apt-get update && apt-get -y upgrade

卸载Apache

apt-get remove apache2

安装nginx,PHP7.0和php7.0-fpm

阅读全文 »

之前把blog搬到了Daocloud上,但似乎最近Daocloud的云端运行环境被玩坏了;之前买了两年的Acrosvm的VPS正好也快到期,正准备续费的时候发现这破玩意儿居然支付不了,发工单给客服也没有回复,果断放弃。

寻找便宜的vps实在是太过于费时费力,而且稳定性还没保障,还是选择个知名的服务商消停消停吧。扫了一圈,发现许多小伙伴用的是Vultr,稳定性还挺不错。所以我注册了PayPal,在Vultr上部署了一个5刀/月,768M内存的最低配服务器。

花了半天时间,手动装了NGINX,PHP7.0和MySQL,顺便给博客启用了https。

后台管理面板的界面设计可以体现出服务商的专业程度。
Screenshot.png

不知不觉一刀就快烧完了T^T, 如果你觉得Vultr不错的话,欢迎用我的邀请链接注册,通过这个链接注册的用户累计消耗$10之后可以为我的Vultr账户增加$10的余额:(新用户注册赠送$5的余额)

Vultr邀请链接

(博主最近穷的要吃土了)

博客一直在用 Typecho 自带的评论,但常常会遇到这种让本博主十分蛋疼的情况:

1.png

于是我在评论设置把回复层数改成了2层

2.png

这样看起来舒服多了,但第二层的评论却没有回复按钮,当我与访客回复多几句的时候访客没注意到上一层的回复按钮,然后就重新开楼回复了。<!--more-->

3.png

经过一番观察发现,把负责评论渲染的类
/var/Widget/Comments/Archive.php 的 reply 方法(大概在472行)的 if 判断中的 !$this->isTopLevel 条件去掉,评论右下角的回复的链接就显示出来了

4.png


阅读全文 »