‘07 . 不上档的三流程序员’ 分类的存档
浏览器用 firefox,平时抓嵌入视频用 flashgot 插件,flashgot一般会调用系统中默认安装的下载工具
但是我不喜欢调用那些工具,而喜欢直接把地址抓出来后用 wget 下载,于是写了一段极简单的猥琐代码
- #!/usr/bin/env python
-
- import os
- import sys
-
- print "\n\n"
- print " ",sys.argv[1]
- print "\n\n\t\tPress any key to exit."
- os.system(‘pause > NUL‘)
然后在 flashgot 里自己添加一下,就可以看到效果了


之前已经实现了 Rainlendar Lite 远程同步 Google Canlendar :http://www.room702.cn/index.php/archives/411
但是若想实现自动化更新还要依靠 Windows 的计划任务,所以今天趁中午短暂的休息将这段代码改为 Windows 的服务
工作很简单,Windows 服务部分完全取自《Python Programming on Win32》书中的代码,这里需要做的仅仅是将之前的代码做些微调:
1、自动循环,每半个小时链接 Google Calendar 一次
2、工作目录修改为 C:\WINDOWS 目录,配置文件也丢到这里
脚本 PyRainlendarSvc.py 地址:http://www.room702.cn/tools/PyRainlendar/PyRainlendarSvc.py.txt
配置文件仍然没变,还是原来那个,只是建议里面指向的ics文件修改为绝对路径,如果不使用绝对路径,ics文件将下载到 C:\WINDOWS 目录,配置文件在这里:http://www.room702.cn/tools/PyRainlendar/PyRainlendar.ini
然后,准备安装:
1、注册 pythonservice.exe :
我使用 Python 2.5,安装 pywin32 后,改文件在 C:\Python25\Lib\site-packages\win32 中
执行命令:pythonservice.exe /register 即可完成注册
2、安装服务
把 PyRainlendarSvc.py 放到一个固定目录中,执行:python PyRainlendarSvc.py install
3、启动服务
执行命令:python PyRainlendarSvc.py start
然后到 services.msc 里将 PyRainlendarClt 服务设置为自动启动
完成后,到 Rainlendar 里将 ics 文件地址重新指向(这些可参考之前的BLOG),这样每隔两个小时 Rainlendar 会从 Google Calendar 更新一次数据
服务启动后,在任务管理器中看到的不是 PyRainlendarSvc 而是 pythonservices.exe ,占用资源不是很大,可以接受


加个开关控制 alters_data 的 True/False 切换
>>> class F:
… var = 100
… def t(self):
… self.var = 200
… t.alters_data = True
…
>>> m = Template(’Var = {{obj1.var}} , do it {{obj1.t}} , Var = {{obj1.var}}’)
>>> o = F()
>>> c = Context({’obj1′:o})
>>> m.render(c)
u’Var = 100 , do it , Var = 100′
>>>
>>>
>>>
>>>
>>> oo = F()
>>> oo.t.__dict__['alters_data'] = False
>>> c = Context({’obj1′:oo})
>>> m.render(c)
u’Var = 100 , do it None , Var = 200′
>>>
perl默认的匹配太贪婪了,今天做个自动分析脚本,匹配的内容总是多出来,最初脚本类似这样:
#!/usr/bin/perl
my $str = ‘AAA=”a1 a2 a3″ BBB=”b1 b2 b3″‘;
if ($str =~ /AAA=”(.*)”/){
print “AAA -> “,$1;
print “\n”;
}
只是想匹配到AAA中的内容,运行结果却是:AAA -> a1 a2 a3″ BBB=”b1 b2 b3
放狗得来的结果很简单,只要把量词改一下就可以了:
#!/usr/bin/perl
my $str = ‘AAA=”a1 a2 a3″ BBB=”b1 b2 b3″‘;
if ($str =~ /AAA=”(.*?)”/){
print “AAA -> “,$1;
print “\n”;
}
注意红色部分,执行结果是:AAA -> a1 a2 a3
这样就是我想要的了
因为家里有多台电脑,所以一直想弄个脚本来做firefox的书签检查,主要是定期检查每台电脑之间的书签分别发生了什么样的变化,以便及时更新和统一书签,也防止一些书签误删
不过做这个的第一步就是要解析firefox的书签,firefox的大部分内容都是通过sqlite来存储的,还算比较容易,sqlite文件在firefox的profiles文件夹中,一般路径是在 %APPDATA%MozillaFirefoxProfiles 目录下有个以default结尾的目录,目录中会有多个sqlite文件,其中 places.sqlite 是最重要的,书签以及访问历史记录都存储在这里
书签不是直接存储在一个特定表里,而是分别在 moz_bookmarks 和 moz_places 两个表中,moz_places中记录了书签还有所有访问过的地址,而moz_bookmarks只是记录了一些书签的id(在moz_bookmarks中体现为 fk 列) 和 书签的名字(moz_bookmarks中体现为title列),而moz_bookmarks 的fk 列 和 moz_places 中的 id 列是对应的,而moz_places 中的 url 列又记录了所有的地址,因此,就有这样的对应关系:
moz_bookmarks 中 :fk —> tilte ,moz_places中: id —> url ,同时:fk == id ,即,两张表通过fk和id来建立联系
当然,除了这些之外,如果需要查找上级目录的话(firefox标签中的目录),还需要考虑到其他列,在这里先把最简单的对应关系搞清楚,其他的以后慢慢再研究了
列出全部书签的id、title和url的代码如下,这里考虑到一些特殊字符的原因,所以title需要用utf-8输出,而Windows的命令行不支持utf-8,所以会看到乱码,不过后期会考虑保存成excel或是xml文件以方便比对,所以这里可以先忽略这个编码问题了 ……
#!/usr/bin/env python
# encoding = gbk
# Python[AT]Live.it
import os
import sys
import codecs
import sqlite3
#moz_places = ‘places.sqlite’
moz_profile = os.getenv(‘appdata‘) + ‘\Mozilla\Firefox\Profiles‘
profiles_dir = os.listdir(moz_profile)
if 1 == len(profiles_dir):
moz_places = moz_profile + ‘\’ + profiles_dir[0] + ‘\places.sqlite‘
else:
print "There are more than one directories in :"
print "t%sn" %moz_profile
c = 1
for i in profiles_dir:
print "[%d] %s\%s" %( c , moz_profile , i )
c = c+1
print "n"
try:
idx = raw_input("Choooooooooose : ")
except KeyboardInterrupt:
print "terminated by user !"
sys.exit(0)
try:
idx = int( idx.strip() )
except ValueError:
print "Error …"
sys.exit(1)
moz_places = moz_profile + ‘\‘ + profiles_dir[idx-1] + ‘\places.sqlite‘
print "n"
#sys.exit(0)
if os.path.exists(moz_places):
pass
else:
print "Can not locate the profilesnt%snt I am dying …" %moz_places
sys.exit(1)
db = sqlite3.connect( moz_places )
cur = db.cursor()
# urls
try:
cur.execute("select id,url from moz_places")
except sqlite3.OperationalError:
print "Database maybe locked , Please shutdown the Firefox browser first."
sys.exit(1)
urls = cur.fetchall()
url_dict = {}
for url in urls:
if None not in url:
url_dict[ url[0] ] = str( url[1] )
# titles
cur.execute("select fk,title from moz_bookmarks")
titles = cur.fetchall()
for item in titles:
if None not in item:
print "id = %s , title = %s , url = %s " %(item[0] , item[1].encode("utf-8") , url_dict[item[0]])
db.close()
# E_O_F
执行截图

Twisted.Network.Programming.Essentials 第二章中的portscan.py 完成了一个端口扫描的功能
代码portscan.py
#!/usr/bin/env python
# Example 2-5
# portscan.py
from twisted.internet import reactor, defer
from connectiontest import testConnect
def handleAllResults(results, ports):
# print results[0]
for port, resultInfo in zip(ports, results):
success, result = resultInfo
if success:
print "Connected to port %i" % port
reactor.stop( )
import sys
host = sys.argv[1]
ports = range(1, 201)
testers = [testConnect(host, port) for port in ports]
defer.DeferredList(testers, consumeErrors=True).addCallback( handleAllResults , ports )
reactor.run( )
代码connectiontest.py
#!/usr/bin/env python
# Example 2-4
# connectiontest.py
from twisted.internet import reactor, defer, protocol
class CallbackAndDisconnectProtocol(protocol.Protocol):
def connectionMade(self):
self.factory.deferred.callback("Connected!")
self.transport.loseConnection( )
class ConnectionTestFactory(protocol.ClientFactory):
protocol = CallbackAndDisconnectProtocol
def __init__(self):
self.deferred = defer.Deferred( )
def clientConnectionFailed(self, connector, reason):
self.deferred.errback(reason)
def testConnect(host, port):
testFactory = ConnectionTestFactory( )
reactor.connectTCP(host, port, testFactory)
return testFactory.deferred
def handleSuccess(result, port):
print "Connected to port %i" % port
reactor.stop( )
def handleFailure(failure, port):
print "Error connecting to port %i: %s" % ( port , failure.getErrorMessage( ) )
reactor.stop( )
if __name__ == "__main__":
import sys
if not len(sys.argv) == 3:
print "Usage: connectiontest.py host port"
sys.exit(1)
host = sys.argv[1]
port = int(sys.argv[2])
connecting = testConnect(host, port)
connecting.addCallback(handleSuccess, port)
connecting.addErrback(handleFailure, port)
reactor.run( )
但是当修改 ports = range(1, 201) 为 ports = range(1, 513) 甚至修改为更大的值时,会出现一个异常:exceptions.ValueError: too many file descriptors in select()
引起异常的原因是由于 Windows 对文件描述符有一定限制,这个限制值是 512 ,而在 Linux 下这个限制为 32767
如果超过这个限制值,就会出现类似上面的异常
关于文件描述符(file descriptor)可参考:http://en.wikipedia.org/wiki/File_descriptor
比之前那个python爬虫简单
简单看了下效果,简单工作应该能应付,还没仔细看代码
sSpider.py.tgz
一只python写的爬虫,以前收集的,好像是来自pypi,还不错
还有几只强大的爬虫,不太容易驾驭,用这个相对简单好用,支持的爬行方式和内容也不少
下载 spider.py.gz
>>> import spider
>>> spider.webspider(b=’http://www.sohu.com’,w=20,d=1,t=10)
(['index.html', 'sohuflash_1.js'], ['http://www.sohu.com/', 'http://www.sohu.com/sohuflash_1.js'])