最近工作需要开发爬虫抓取别人网页的数据,由于IP有限为避免被封只能采取各种混淆手段,其中一种是伪造X-Forwarded-For的请求头,尽管起作用的可能很小(若是Nginx上做限制的话直接无视这个……),但毕竟多一个算一个。既然做了就得做专业一点,那混淆的IP当然就不能随机了,必须满足确定的地理位置,最后发现国外有家MaxMind提供免费的GeoIP数据。下载回来的数据中包含两个文件,其中一个是IP数据,另外一个是对应的地理信息:

GeoLiteCity-Blocks.csv
1
2
3
4
5
6
Copyright (c) 2011 MaxMind Inc.  All Rights Reserved.
startIpNum,endIpNum,locId
"16777216","16777471","17"
"16777472","16777727","104084"
"16777728","16778239","49"
"16778240","16778751","14409"
GeoLiteCity-Location.csv
1
2
3
4
5
6
7
8
Copyright (c) 2012 MaxMind LLC.  All Rights Reserved.
locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode
1,"O1","","","",0.0000,0.0000,,
2,"AP","","","",35.0000,105.0000,,

414266,"CN","30","Hegu","",22.5970,112.8044,,
414267,"CN","16","Pingchihsu","",22.1500,108.7500,,
414268,"CN","30","Dadu","",22.9785,113.1684,,

数据基本上都很好理解,唯一一个问题是IP地址是用整形表示的,要还原出我们熟悉的IP格式的话还需要对其进行转换:

阅读全文 »

Fabric是Python的远程SSH命令行工具,常用来实现服务远程管理及持续化部署。最近需要在集群中执行离线任务,在官方文档中有例子:

run("nohup yes >& /dev/null < /dev/null &")

但按照这种写法在实际操作中并无法正确执行相应的任务,折腾一阵后发现这是由于Fabric过早关闭了连接的Session导致的,可以用一个小技巧避免这个问题:

run("$(nohup yes >& /dev/null < /dev/null &) && sleep 1")

在用代码处理Excel文件中的日期数据时,读出来的是一个数值,这是因为在Excel中日期数据实际存储为距离1900-01-01的天数,因此需要转换才能得到正确的日期。

Excel Date Convertor
1
2
3
4
5
import datettime
def convert(ordinal):
"""Convert Excel Date type"""
sd = datetime.date(1899, 12, 31)
return datetime.datetime.fromordinal(int(ordinal) + sd.toordinal()) - datetime.timedelta(days=1)

以2013-05-28为例,该日期在Excel中存储为41422,转换后:

>>> convert(41422)
datetime.datetime(2013, 5, 28, 0, 0)

Intro

Ganglia是一个分布式的开源集群监控系统,主要包括gmond,gmetad,gweb三个模块,其独特的网状结构具备强大的伸缩性,通过组播(multicast)/UDP的的通信方式Ganglia可以很轻松监控成千上万(丝毫不夸张)的服务器集群,且不存在单点故障的问题。

Deploy

Ganglia代码托管在SourceForge上,代码中自带RPM编译定义文件,通过rpmbuild可以很容易编译出RPM包:

rpmbuild -bb ganglia.spec

rpmbuild -bb ganglia-web.spec

以CentOS x86平台为例,最后得到一系列的软件包:

  • libganglia-3.5.0-1.i386.rpm
  • ganglia-devel-3.5.0-1.i386.rpm
  • ganglia-gmond-3.5.0-1.i386.rpm
  • ganglia-gmetad-3.5.0-1.i386.rpm
  • ganglia-gmond-modules-python-3.5.0-1.i386.rpm
  • ganglia-web-3.5.7-1.noarch.rpm
阅读全文 »

神一般的星座JS函数,完全理解不能……

Constellation Magic
1
2
3
function getAstro(m, d) {
return "魔羯水瓶双鱼牡羊金牛双子巨蟹狮子处女天秤天蝎射手魔羯".substr(m*2-(d<"102123444543".charAt(m-1)- -19)*2,2);
}

在网页数据展示中,分页是很普遍的操作,在分页逻辑中需要根据数据数据与页面大小计算出页数。对于小数据来说,获取数据集大小的开销可以忽略,但对百万级以上的数据来说,如果不通过合适的优化,随意查询数据集大小的时间开销是恐怖的。这里介绍两种优化的手段:

Query with Primary Key ONLY

减少查询的内容有助于提高查询速度,这点与避免SELECT *是一样的,对于表结构比较复杂以及无法利用covering index的场景来说,计算数据集大小时只考虑主键将极大地提高性能。

Query with ID ONLY
1
count = session.query(Model.id).count()

Approximate Count

对于不需要查询条件的场景来说,直接读取表状态也是一种很好的策略。虽然这种查询的结果不够准确,但对于百万级的数据来说这点误差应该是可以接受的,在处理到需要精确值的环节时再改用别的方法就好了。以下是SQLAlchemy的一个实现:

Count with SHOW TABLE STATUS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def approximate_count(session, table_name):
"""
通过 `SHOW TABLE STATUS` 方法快速查询数据表大小

:param session: SQLAlchemy `Session`
:param table_name: 数据表名
:type table_name: str
"""

result = session.execute('SHOW TABLE STATUS WHERE Name = :table_name', {
'table_name': table_name }).first()

if not result:
raise NoSuchTableError(table_name)

return result['Rows']

在InnoDB中,数据库通过multi-versioning为查询提供数据快照,查询语句不受非当前事务下的其他操作影响。在默认的REPEATABLE READ隔离等级下,事务中的一致性读操作都将基于该事务第一次执行查询时所建立的快照,这其中有两个值得注意的问题:

数据库的虚拟状态

由于事务中只能看到当前事务内对数据库的修改,因此要是在事务A中对数据库进行了修改,同时另一事务B也进行了修改操作并结束事务的话,事务A中此后看到的数据状态并没有真正存在过。以具体例子说明,首先创建一个测试数据库:

InnoDB Initialize Script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE test (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
value SMALLINT,
msg CHAR(255)
);


CREATE INDEX idx ON test (value);

START TRANSACTION;
INSERT INTO test (value, msg) VALUES
(1, 'Hello'),
(3, 'World'),
(4, 'Foo'),
(5, 'Bar');

COMMIT;
阅读全文 »