2011年8月

lxml 加 beautifulsoup with 多线程(Snail)

抓取的时候,去获取网页中指定的内容,最基本的办法就是使用正则获取,但要是要处理的网站多了,写正则岂不写死。于是哥就写了个类,看代码:

蜗牛号基类

# -*- coding: utf-8 -*-
import threading, Queue
import urllib2, cookielib
from lxml.html.soupparser import fromstring

class Snail(threading.Thread):
	def __init__(self , *argv):
		self.buildBrowser(*argv)
		super(Snail, self).__init__()
	def buildBrowser(self, *argv):
		self.cookie = cookielib.CookieJar()
		opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie))
		opener.addheaders = []
		opener.addheaders.append(('User-Agent', 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.904.0 Safari/535.7'))
		opener.addheaders.append(('Accept', '*/*'))
		opener.addheaders = opener.addheaders + [t for t in argv]
		urllib2.install_opener(opener)
	def parse(self, link, data = None):
		content = self.handle(link, data).read()
		tree = fromstring(content)
		return tree
	def handle(self, link, data = None):
		return urllib2.urlopen(urllib2.Request(link, data))
	def save(self):
		pass
snail = Snail(('Cookie','这边可以自己填写'))

需要lxml模块支持,可以到 http://lxml.de/ 下载,centos下的安装方法:

yum -y install libxml2-dev libxslt-devel
cd /usr/local/src
wget http://lxml.de/files/lxml-2.3.2.tgz
tar vzxf lxml-2.3.2.tgz
cd lxml-2.3.2
python setup.py install

cd ../
wget http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.2.0.tar.gz
tar vzxf BeautifulSoup-3.2.0.tar.gz
cd BeautifulSoup-3.2.0
python setup.py install

基类的使用实例

线程锁rlock

# -*- coding: utf-8 -*-
from Snail import Snail
import threading

rlock = threading.RLock()
class Mphone(Snail):
	def __init__(self):
		super(Snail, self).__init__()
	def process(self, numhead):
		#做点实际处理的事情
		pass
	def run(self):
		while True:
			rlock.acquire()
			#线程锁锁定资源的时候,取值
			rlock.release()
			#可以在某个特定条件下 break 掉循环
			self.process(numhead)
if __name__ == '__main__':
	threadnum = 4
	threads = []
	for i in range(threadnum):
		mphone = Mphone()
		threads.append(mphone)
	for i in range(threadnum):
		threads[i].start()
	for i in range(threadnum):
		threads[i].join()

可能会遇到的一些问题

TypeError: cannot concatenate 'str' and 'NoneType' objects
#解决办法
unicode('这边是要解析的字符串', 'utf-8', errors='ignore')

php调用python服务

侃侃:公司用的php的popen以命令的形式调用python,首先说说这样做的缺点。

php执行命令行调用python的缺点

popen('python test.py [参数]', 'r');
  1. 缺点一:windows默认的是gbk编码,当php中传utf-8中文参数的时候,python接收到的参数会有问题。

    #当然,这是有解决的办法的,就是windows下转换一下字符的编码,linux不用转换。再来python接收参数的时候肯定也要转换编码了,烦不烦?
  2. cmd命令或者shell命令是有长度限制的,传的参数过长的时候,接收到的参数就不会完整。
  3. 执行shell命令是有危险的,万一参数里面多了个啥,你知道的。

    #这也能解决,php中的函数escapeshellarg,嗯哼先给他escape一下。
    

那怎么办呢?

python socket server

不多说,不清楚的百度"socket",下面上代码(写的一个php调用python服务美化javascript的应用,服务器端python):

#代码中引用的模块将会在附件中给出
import sys, json
import traceback
import SocketServer
from daemon import Daemon
import jsbeautifier

class Todo:
    def __init__(self):
        print('Welcome!')
    def test(self, args):
        res = jsbeautifier.beautify(args[0].encode('utf-8'))
        return res;
    def error(self, args):
        return 'not function!'

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                data = self.request.recv(1024)
                if not data:
                    print('end')
                    break
                data = json.loads(data)
                res =  getattr(self._object, data['func'], 'error')(data['args'])
                if not res:
                    res = ''
                res = str(len(res)).rjust(8, '0') + str(res)
                self.request.send(res)
            except:
                print('error in ThreadedTCPRequestHandler :%s, res:%s' % (traceback.format_exc(), data))

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

class Server(Daemon):        
    def conf(self, host, port, obj):
        self.host = host
        self.port = port
        self.obj = obj
        ThreadedTCPServer.allow_reuse_address = True
    def run(self):
        ThreadedTCPRequestHandler._object = self.obj
        server = ThreadedTCPServer((self.host, self.port), ThreadedTCPRequestHandler)
        server.serve_forever()

if __name__ == '__main__':
    server = Server('/tmp/daemon-tortoise.pid')
    server.conf('0.0.0.0', 1990, Todo())
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            server.start()
        elif 'stop' == sys.argv[1]:
            server.stop()
        elif 'restart' == sys.argv[1]:
            server.restart()
        else:
            print("Unknown command")
            sys.exit(2)
        sys.exit(0)
    else:
        print("usage: %s start|stop|restart" % sys.argv[0])
        sys.exit(2)

解释一下,上面这些代码是用python创建一个socket服务器,并且加入系统的守护进程。Todo里面实现策略工厂啥的,你懂的。使用方法:

python sever.py [start|stop|restart]
#接着设为系统启动项就O了。

php通过socket调用python

//代码中引用的文件将会在附件中给出,附件中还给出了php并发的写法
require 'socketapi.php';
header("Content-type: text/html; charset=utf-8");
$s = new server('192.168.1.8', 1990);
$code = <<<EOT
/*   美化:格式化代码,使之容易阅读            */
/*   净化:去掉代码中多余的注释、换行、空格等    */
/*   压缩:将代码压缩为更小体积,便于传输        */
/*   解压:将压缩后的代码转换为人可以阅读的格式    */

/*   如果有用,请别忘了推荐给你的朋友:        */
/*   javascript在线美化、净化、压缩、解压:http://box.inote.cc/js   */

/*   以下是演示代码                */

    var getPositionLite = function(el) {        var x = 0,        y = 0;        while (el) {            x += el.offsetLeft || 0;            y += el.offsetTop || 0;            el = el.offsetParent        }        return {            x: x,            y: y        }    };
/*   更新记录:                    */
    var history = {
        'v1.0':    ['2011-01-18','javascript工具上线']
    };
EOT;
$res = $s->obj('Todo')->test($code);
echo '<pre>'.$res.'</pre>';

附件,你懂的。

client.zip | server.zip

bash杂记

带有颜色的echo

设置颜色的格式: e[背景色;前景色;高亮me[0m

e或033
背景色:0 透明(使用终端颜色), 40 黑, 41 红, 42 绿, 43 黄, 44 蓝 45 紫, 46 青绿, 47白(灰)
前景色:30 黑 31 红, 32 绿, 33 黄, 34 蓝, 35 紫, 36 青绿, 37 白(灰)
高亮:高亮是1,不高亮是0。(m后面紧跟字符串)

#红色的helloworld
echo -e '\033[0;31;1mhelloworld\033[0m'

screen命令

在SSH断开的情况下,服务器端继续执行程序。

screen -S test
#输入要执行的命令,enter
#Ctrl + a + d保存screen
#查看所有screen
screen -ls
#恢复screen
screen -r test
#退出screen
exit

crontab命令

crontab [-u 用户名] [-elr]
#crontab -e
#分  时  日  月  周    [用户]  command
#每分钟执行一次第一个参数可以写成样 1-59 或者 */1
# .---------------- minute (0 - 59) 
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ... 
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)  OR sun,mon,tue,wed,thu,fri,sat 
# |  |  |  |  |
# *  *  *  *  *  command to be executed

crontab中的环境变量问题

有时候crontab执行脚本获取不到想要的结果,而直接在ssh里执行的时候是正常的,就是环境变量的问题,在要执行的脚本中加入下面两行。

. /etc/profile
. ~/.bash_profile

计算程序运行时间

time ./test

linux文件压缩解压

.tar
解包: tar xvf FileName.tar
打包:tar cvf FileName.tar DirName
(注:tar是打包,不是压缩!)
---------------------------------------------
.gz
解压1:gunzip FileName.gz
解压2:gzip -d FileName.gz
压缩:gzip FileName
.tar.gz
解压:tar zxvf FileName.tar.gz
压缩:tar zcvf FileName.tar.gz DirName
---------------------------------------------
.bz2
解压1:bzip2 -d FileName.bz2
解压2:bunzip2 FileName.bz2
压缩: bzip2 -z FileName
.tar.bz2
解压:tar jxvf FileName.tar.bz2
压缩:tar jcvf FileName.tar.bz2 DirName
---------------------------------------------
.bz
解压1:bzip2 -d FileName.bz
解压2:bunzip2 FileName.bz
.tar.bz
解压:tar jxvf FileName.tar.bz
---------------------------------------------
.Z
解压:uncompress FileName.Z
压缩:compress FileName
.tar.Z
解压:tar Zxvf FileName.tar.Z
压缩:tar Zcvf FileName.tar.Z DirName
---------------------------------------------
.tgz
解压:tar zxvf FileName.tgz
.tar.tgz
解压:tar zxvf FileName.tar.tgz
压缩:tar zcvf FileName.tar.tgz FileName
---------------------------------------------
.zip
解压:unzip FileName.zip
压缩:zip FileName.zip DirName

设置开机启动

vi /etc/rc.d/rc.local

SCP命令

scp -r root@type.so:/var/www/html/ -P 22 /var/www/html/

rpm

# 导出文件
rpm2cpio file.rpm | cpio -div
# 查看rpm包列表内容
rpm -qpl file.rpm

修改时区

cp /usr/share/zoneinfo/Shanghai /etc/localtime
hwclock -w
# crontab重启必须的,不然设定的动作将会按照老的时间来
service crond restart

python杂记

python实现switch语句

{
    '0' : labmda : print('你是男的还是女的'),
    '1' : labmda : print('你是男的'),
    '2' : labmda : print('你是女的'),
}.get('1')()

python实现三目运算

#example1
(labmda x,y: x < y and x or y)(1,3)
#example2
(labmda x,y: x if x < y else y)(2,4)

python中exec和eval的用法

#example exec
exec("mult = lambda x,y: x**y")
print(mult(2, 3))
#example eval
print(eval("lambda x,y: x**y")(2,3))

python中enumerate带索引的遍历

str = 'mystring'
#lst = ['hello',',','type','.','so']
for idx , ele in enumerate(str):
    print(idx,ele)

python中for else语句

import math
for i in range(100):
    for t in range(2, int(math.sqrt(i)) + 1):
        if i % t == 0:
            break
    else:
        print(i)

python动态导入模块

mymod=__import__('mypackage', fromlist=["*"])
mymod.mydef()

python按行读取文件

#sample 基本的方法
file = open("sample.txt")
while True:
    line = file.readline()
    if not line:
        break
    pass
#sample 更快的方法
file = open("sample.txt")
while True:
    lines = file.readlines(100000)
    if not lines:
        break
    for line in lines:
        pass

python html中编码的汉字

抓取网页的时候可能会遇到(小子)这样的格式输出的汉字,我们想办法将他还原为真正的汉字

#10进制的
print(unichr(int('23567', 10)))
print(unichr(int('23376', 10)))
#16进制的
print(unichr(int('0x5c0f', 16)))
print(unichr(int('5b50', 16)))
#用HTMLParser模块
import HTMLParser
html_parser = HTMLParser.HTMLParser()
s = html_parser.unescape('小子')
print(s)

获取本机IP

import socket
print(socket.getaddrinfo(socket.gethostname(),None)[-1][4][0])

python中list相减

python中两个list可以相加,却不能相减,是不是很纠结。

list1 = [1, 2, 3, 4, 5]
list2 = [1, 3, 5]
#example1 转换为集合相减
list3 = list(set(list1) - set(list2))
#example2
list3 = [i for i in list1 if i not in list2]

判断list1是否为list2的子集

list1 = [1,3,5]
list2 = [1,3,5,7]
if all(x in list2 for x in list1):
    print('子集')

读取大文件的指定行

def getline(thefilepath, desired_line_number): 
    if desired_line_number < 1: return ''
    for current_line_number, line in enumerate(open(thefilepath, 'rU')): 
        if current_line_number == desired_line_number-1: return line
    return ''

print写文件

f = open('out.txt','w+')
print >> f, 'hello', 'world'
f.close()

元祖传递函数参数

def add(a, b):
    print a + b
opnds = (1,2)
add(*opnds)

单词首字母大写

string.capwords

我愿化身石桥

shiqiao.jpg

我愿化身石桥,受五百年风吹,五百年日晒,五百年雨打,但求那少女从桥上走过……