简单的爬虫实验

说下背景,起因是因为公司业务上有一块,功能出现了问题,用户的设备端在去请求一个xml 文件的时候,发现从服务器总是下载出错,或者下载超级的慢,因为现有的环境是国外的客户的设备全部都链接到了国内的阿里云的服务器,然后导致下载异常的慢,所以现在想让过外的客户在下载文件的时候,可以判断如果设备端在国外,那么就重定向去新加坡的阿里云OSS 下载,否则国内的IP地址的用户就重定向到国内的阿里云OSS地址下载.

1. 首先,设备端是通过http请求来下载文件的,所以我唯一可以知道的是设备端连接过来的remoteaddr 地址.
2. 设个时候我就可以通过remoteaddr 地址去判断用户的设备到底处于国内还是国外,因为用户的设备有可能是移动的
3. 这个时候就找到了一个淘宝的IP地址库查询接口:http://ip.taobao.com/ipSearch.php
4. 就根据这个区请求查询IP地址的位置,然后做相应的地址重定向
5. 存在的问题,淘宝IP地址库的查询请求是有频率限制的,所以会存在频繁查询查询失败的情况,这个时候是默认跳新加坡的,因为我们主要的客户在国外

好了一下说正事~

淘宝的IP库,看起来就是给出了比较详细的信息:

这个时候,我就像做一个我自己的地址库,然后让别人来查,看了下,上面有的信息,这时候网上了查了下,好像可行,就开始动手了.
需要的信息:
1. 国家, 国家代码
2. 省,省代码
3. 市,市代码
4. isp
5. IP地址库
相应的地址,在代码里面有,需要的可以看代码的请求地址

去网上搜索了一下,好像这些大概都可以找到,接下来就去爬下来就好了(无奈IP地址库的信息,现在我只找到了省级以上的地址库的信息,最后也没找全.

国家代码再维基百科上爬的

个人经验要点:
1. 爬基本的信息的时候,如果遇到整页信息的,其实可以不用http 请求,特别是想国外网站的(维基百科),不科学上网还请求不下来,这个时候就直接手动复制一下,然后读入解析就好了,我维基百科就是直接辅助文件,然后解析文件的

2. 遇到二级或者三级页面的时候,可以自己手动点击一下,然后看看页面的跳转,因为大批量类似页面的时候,有时候可能只需要改变页面的一个字符就可以直接请求了

3. 关键点在解析部分,这里我用的是python + BeautifulSoup 爬的,之前我想用go爬,却发现做正则表达式匹配的时候非常困难,然后爬了一个就改为用python了
BeautifulSoup 好像可以直接过滤掉&nbsp这类的字符,然后有很多的接口可以直接调用,获取到title 之类的html 标签,很方便

4. 当爬到纯文本的时候,这个时候要读取行或者列的时候,用字符串的分隔,分成数组,来挑选其中需要的项,我觉得这样是比较方便的。

5. 注意请求头要加一下一些基本的http 请求头信息,否则有的网站会识别,然后不会回应你.

6. 封装请求html 下载页面内容的方法,再解析想要的内容,存入数据库即可。

7. 服务部分就可以直接写服务,读取相应的数据库,查询,提供服务即可。

golang reflect 测试

Intellj IDEA 配置go 开发环境

1. 下载安装版本go 1.8

2. 按照提示下一步下一步安装好 go 后,应该是在C:\Go 目录
3. 可以在cmd 命令行$go 试试看能不能答应出usag
4. mac 可以使用homebrew 安装,安装完后应该是在homebrew 下的Celler 下面
5. 配置gopath 目录指向一个你用于存放go 源码、包、可执行文件的目录,
并且go 强制要求在此目录下简历src bin pkg目录存储相关的go 源码文件和包文件
当你使用go get github.com/urlshor…..之类的包的时候就会存储在这些src 目录下了
6. 下载安装intellj IDEA , 地址:http://www.jetbrains.com/idea/
激活可以使用licenseServer 激活,server可以使用:http://idea.iteblog.com/key.php

7. 启动idea ,并在config中找到plugins ->browse repositories中输入go 安装go language
8. 新建项目 配置go sdk 选择你安装go的目录,也就是那个C:\Go 目录
9. 编写go 代码
#10. 关于包的管理,IDEA 强制包名同目录名,如果你想建立一个package在本地,然后main 包引用
那么你需要建立相应的目录在src 目录中,然后通过import “./packagename” 引入

How to configure and make a open source code

How to make a open source code

        或许我们经常会遇到这样的问题,就是如何去把我们使用到的一个open source 的code 放入自己的代码库,方便自己的编译,有多方便呢?就是当新人来的时候,可以不用这里找找,那里改改。当服务器突然被某个新手一不小心搞挂的时候,重新搭建服务器后,依旧可以快速顺利的编译完整个工程代码.(我记得我那时候是小白的时候也曾三次搞挂公司编译服务器.然后每次重新装一次编译服务器都要搞个半天一天的,还被骂.

以下是我编译的经验.

1. 如果你要新加入一个open source 的code,那么你可以新建一个open source 的code相关的目录,一般就直接建成open source的名字就好了,记得不要加任何版本相关的信息.

2. 把下载下来的 open source XXXX.tar.gz 的原始包放进目录,然后解压文件.

3. 在 自己建立的目录加一个Makefile 作为自己的编译,所有你需要配置的,clean  install  distclean 的选项都从新自己写一遍.

4.  这时候在现有的Makefile 中编写configure 的脚本,当然我们每次git clone code 的时候,可能每台机器,或者自己的目录都不一样,这时候可能在自己这台机器配置完的,然后git push上去仓库的代码,再别人那里又编译不过了,所以configure 最好是每次git clone code的时候都做一次配置,确保每台机器都是更加机器的现有配置来配置open source code, 但是还有一个问题就是,我们自己git clone 代码的时候,应该配置完一次后,第二次则不应该再重新配置,除非使用make distclean 清楚配置后. 这里我们可以根据open source code 目录下面是否有Makefile 文件来判断是否进行configure ,因为很多的open source code Makefile是动态生成的.

5. 每个我们编译的open source code 基本都是默认配置在用户编译的机器使用,所以采用的编译选项和安装选项基本都是x86 的配置,这时候如果你做的是嵌入式的东西,使用到交叉编译记得配置使用 cross cc 交叉编译环变量,另外一个需要注意的就是配置prefix 选项,这个选项会涉及到你在make install 的时候应该安装到哪里,以及当你的程序运行时,应该在你的嵌入式环境中哪里去链接动态库, 所以这里我比较建议的是配置成自己的嵌入式环境的目录结构下,open source 运行的目录结构. 然后在你建立的目录结构中增加一个 BIN 相关的目录,在Makefile中做make install 的时候把编译的版本需要的binary 自己写cp 命令拷贝到BIN 目录下边,在打包的时候再拷贝到自己是target下面。

6. 基本编译的问题解决了,这时候可能你还会涉及到改动open source code 相关的东西. 建议大家可以首先考虑配置是否能解决(我记得我曾经就编一个rip 的时候本来可以用配置解决的,我却搞了半天想去改代码,最后发现配置一下配置文件就搞定了),如果非要改open source的代码的时候,可以先把现有的刚刚解压出来,没有编译和configure的代码先上库,然后再在Makefile中添加一个macro 宏定义 ,用宏定义包含自己要修改的代码范围,这样可以控制编译的时候编原始代码还是编译自己修改过的代码.  还有一个比较重要的问题,就是我发现很多小企业不重视LICENSE 这种问题(我个人觉得这是一个比较重要的问题,就像小米被告一样,如果一个企业要想搞大,那就必须注意license 问题,注意给出GPL ,也可以定义自己的license),如果涉及到license ,可能我们还需要在建立的目录下添加一个GPL 的目录作为编译GPL release用.

7. 然后如果要做版本升级的时候,只需要重新下载一下新版本的open source XXX.tar.gz 然后合一下你自己的改动(去查commit log),然后改动一下Makefile 编译的版本即可解决升级的问题,而且还不用创建一大堆的各种版本的目录,和配置各种版本。

8. 我给出一个我配置lighttpd 写的Makefile 做一个example:

目前我还存在的疑问:现在我编译samba的时候,我发现我配置完prefix后,编译可以通过了,但是当我做make install 的时候,install到自己的目录的时候会出错,也就是:make install DESTDIR=”samba/BIN/”
但是如果我配置prefix目录为 “samba/bin/” 的时候,我make install 的时候回正常,但是当我放进去板子跑的时候又会出现连接库文件的时候找不到,出现运行出错.

目前这个问题我还不知道怎么解决,还期待有人可以指导指导这样的问题该怎么配置会比较好。

写得不对的欢迎拍砖.
本文章版权归作者所有,如有转载,请注原始出处,并通知作者.

QDBM数据库 C API接口中文版

QDBM 基本调用API规范
VERSION 1
(此文档非正式文档,仅仅是我自己为了便于自己理解qdbm api 接口调用顺便翻译。转载请注明出处!-20161018-lgm)

概述
QDBM 是一个常规的管理型数据库调用库。这个数据库是一种简单的记录型数据库,每一条记录是一个包含key 和value的键值对.每一对key和value是一个可变长的字节序.二进制形式和字符串形式都可以作为他的key和value.它是一个没有表格也没有数据类型的一种数据库形式。每条记录以hash表或者B+ 树的形式组织。
关于这种hash表形式的数据库,每一个key在数据库中必须是唯一,因此不可能存在两个或多个key 完全一样的记录.以下我们提供了一系列的方法来访问数据库,比如:通过一个key和value存储一条记录,通过一个key删除一条记录,通过一个key检索一条记录,此外,遍历每一条记录,当然顺序是随意的我们不进行排序。在linux中访问数据库的方法和大多数的DBM (NDBM ,GDBM)具有类似的接口定义。QDBM 是一个好的方式去替代其它数据库,因为它具有较好的性能表现。
相对于hash 表,B+树形式存储,它是可以存储重复的key值记录的。同样的增加,删除,遍历,查找的我们也提供类似hash表的API调用。记录可以通过用户定义排序方法顺序的存储。我们可以通过一个游标以升序或者降序的形式访问,根据这种机制呢,我们可以做一个字符串的匹配的查询,或者实现一个整数范围内的查询。此外,遍历数据库记录在B+ 树也是可用的。
QDBM是用C写的一个数据库,提供有一系列语言的API,其中包括有C,C++.JAVA,Perl, 和Ruby。QDBM在所有符合POSIX标准的平台上这些API都是可用的。QDBM 是一个在LGPL License 授权下试用的免费使用的软件。

基础API:
Depot 是QDBM的一个基础API,实现了几乎所有用于管理QDBM数据库功能的API调用。其它的API调用基本上只是把Depot API调用做了一次包装。Depot是所有API调用中最快的。为了你能正常的使用Depot , 你需要在你的源文件中包含”depot.h”头文件和”stdlib.h”头文件。通常情况下这两个文件我们应该把它放在源文件的最开始的位置。

#include <depot.h>

#include <stdlib.h>

一个用于指向数据库操作的句柄指针 “DEPOT”,这也就是好比如我们需要操作文件时使用的”stdio.h”里面用的”FILE” 文件指针。数据库可以通过“dpopen”函数调用打开,通过“dpclose”函数调用关闭。你不应该直接手动去操作数据库句柄的成员,如果出现了致命错误,除了关闭操作”dpclose”方法,任何的访问方法都会不正常并且会返回一个错误状态代码。同一个进程可以同时使用两个数据库操作句柄,但是同时操作同一个数据库文件我们并不建议你这样去操作。
API
extern const char *dpversion;
“dpversion”全局外部变量是一个字符串变量,定义了版本相关的信息。

extern int dpcode
“dpcode”全局外部变量定义了最后的错误状态码,所有的错误状态码的详细信息我们都可以在“depot.h”头文件中查到。初始变量值是“DP_ENOERR”,其它定义有的值还有以下值:DP_EFATAL', DP_EMODE’, DP_EBROKEN', DP_EKEEP’, DP_ENOITEM', DP_EALLOC’, DP_EMAP', DP_EOPEN’, DP_ECLOSE', DP_ETRUNC’, DP_ESYNC', DP_ESTAT’, DP_ESEEK', DP_EREAD’, DP_EWRITE', DP_ELOCK’, DP_EUNLINK', DP_EMKDIR’, DP_ERMDIR', and DP_EMISC’.

const char *dperrmsg(int code)
“ecode”指一个特定的错误代码,函数的返回值是一个不可写的错误代码对应的错误信息字符串。

DEPOT *dpopen(const char *name, int omode, int bnum);
“name”是指定的数据库名称。“omode”是指定连接数据库所要进行的操作:“DP_OWRITER”指定写,“DP_OREADER”指定读,如果指定的操作模式是“DP_OWRITER”,那么你可能需要对操作模式操作做一个与的操作,进行“DP_OCREAT”,也就是说当数据库不存在的时候创建新的数据库文件。“DP_OTRUNC”操作意味着不管数据库存在或者不存在我们都创建一个新的数据库文件。对于“DP_OREADER”读操作和“DP_OWRITER”写操作,我们可以与上一个“DP_ONOLCK”操作,这意味着我们操作数据库的时候将不对数据文件上锁,或者我们可以与上一个“DP_OLCKNB“操作,这就意味着我们执行非阻塞式打开。对于“DP_OCREAT”
操作可以或上“DP_OSPARSE”操作,这代表创建一个松散的数据库文件。“bnum”代表元素阵列的数组元素个数,如果不大于0,则使用默认值,这一个阵列值是在创建数据库时就决定了的,并且通常情况下是不能改变的。建议的阵列数组大小设置为0.5到4的范围内。函数的返回值是一个数据库的操作句柄,如果返回NULL则代表数据库打开不成功,当以写方式打开数据库文件时,我们会对数据库执行独占写锁的调用,当以读方式打开时,我们会对数据库文件执行共享读锁调用,打开线程会阻塞,直到数据库被锁定,如果使用了“DP_ONOLCK”模式操作,则应用程序应该负责控制数据库文件的锁定。

Int dpclose(DEPOT *depot)
“depot”代表一个数据库操作句柄。如果函数调用成功,返回值为true否则返回false。关闭数据库操作句柄后,我们就不应该再继续使用此句柄。如果是更新数据,我们应该在数据库句柄关闭前写入数据。如果是以写方式打开数据库,但是又没有关闭数据库,则这个数据库将会被破坏。

Int dpput(DEPOT *depot)
“depot”是一个写操作的数据库句柄。“kbuf”是一个指向需要写的数据域的Key指针,”ksiz”是一个表示key数据域长度大小值,如果这个数是一个负数,这个大小通过“strlen(kbuf)”分配。“vbuf”是一个表示value数据域的指针,“vsiz”是一个表示value数据域长度的值,如果是负数,这个大小通过“strlen(vbuf)”分配,“dmode”表示如果出现重复key的时候所要进行的操作,可以有以下值:”DP_DOVER”表示覆盖现有的存在的值,“DP_DKEEP”表示保持现有数据库的值,“DP_DCAT”表示指定的值连接到现有值的末尾,如果函数执行成功返回true否则返回false。

Int dpout(DEPOT *depot, const char *kbuf, int ksiz)
“dpout”函数表示用于删除一条记录,“depot”表示一个写操作的数据库句柄,“kbuf”表示一个指向key数据域的一个指针,”ksiz”表示key数据域的大小。如果为负数,则大小通过“strlen(kbuf)”计算分配。如果函数执行成功,返回true否则返货false。 返回false表明函数执行失败,数据库中不存在这这要上出的key 的数据库记录。

char *dpget(DEPOT *depot, const char*kbuf, int ksiz, int start, int max, int *sp);
“dpget”用于检索获取一条数据库记录。“depot”表示数据库操作句柄,“kbuf”表示一个key数据域指针,“ksiz”表示key数据域指针的大小,如果为负数,则key数据域指针使用“strlen(kbuf)”计算分配大小,“start”表示检索的起始数据库记录偏移,”max”表示读取的最大的数据库记录数,如果为负数,则表示无限制。“sp”表示一个用户返回数据库记录的变量的指针,如果为NULL,表示不适用此指针。如果函数执行成功,返回指向相应数据记录的指针,否则返回NULL。如果返回NULL,表明没有相应的key 值的记录存在数据库中,或者是size的值小于start的起始的值。由于返回的记录值会在末尾追加一个结束符‘\0’,所以返回值可以当做一个字符串进行处理。由于返回值的指针区域是使用malloc 函数动态分配的,所以在使用完后应该做release释放处理。

int dpgetwb(DEPOT *depot, const char *kbuf, int ksiz, int start, int max, char *vbuf);
“dpgetwb” 是用于检索一条数据库记录,并存入指定的指针区域。“depot”指向需要操作的数据库句柄。“kbuf”是一个指向key数据域的指针。“ksiz”表示key数据域的大小。如果为负数,则大小使用“strlen(kbuf)”计算。”start”表示开始检索的数据库记录的起始偏移地址。
“max”表示检索的最大长度。最大应该小于或等于缓冲区的大小。“vbuf”表示检索出的数据库记录的value值存储的buffer 地址。如果函数调用成功,返回写入”vbuf”的数据大小,否则返回“-1”.返回“-1”还有可能是数据库没有指定的key值的记录,或者查询的size大小小于开始start偏移量。注意查询的结果写入进“vbuf”是不带结束符‘\0’的。

1 2 3 4 20