我像一顆棋子,被上帝抓在手中,我看到她的眼卻廳不到她的心. 注册 | 登陆

Python 写的简易采集爬虫

# 简易采集爬虫
# 1.我只做了一个收集url的功能,如果需要将数据入库,可在 parseData 函数里面写处理代码
# 2.需要sqlite3或者pysqlite支持
# 3.可以在DreamHost.com空间上面运行
# 4.可以修改User-Agent冒充搜索引擎蜘蛛
# 5.可以设置暂停的时间,控制采集速度
# Author: Lukin<mylukin@gmail.com>
# Date : 2008-09-25

#!/usr/bin/python

#-*-coding:utf-8-*-


# 简易采集爬虫

#     1.我只做了一个收集url的功能,如果需要将数据入库,可在 parseData 函数里面写处理代码

#     2.需要sqlite3或者pysqlite支持

#     3.可以在DreamHost.com空间上面运行

#     4.可以修改User-Agent冒充搜索引擎蜘蛛

#     5.可以设置暂停的时间,控制采集速度

# Author: Lukin<mylukin@gmail.com>

# Date     : 2008-09-25


# 导入采集需要用到的模块

import resystime

import httplib
os.path as osp

from urlparse import urlparse

# 使用sqite数据库,为了兼容DreamHost.com的空间,只能这么写了

try :

     
import sqlite3 as sqlite

except ImportError
:

     
from pysqlite2 import dbapi2 as sqlite


# 采集速度控制,单位秒

sleep 1

# 设置提交的header头

headers = {"Accept""*/*","Referer""http://answers.yahoo.com/","User-Agent""Mozilla/5.0+(compatible;+Googlebot/2.1;++http://www.google.com/bot.html)"}

# 连接服务器

dl httplib.HTTPConnection('answers.yahoo.com')

# 连接数据库

conn sqlite.connect(osp.abspath('./database.db'))


# 创建数据库

def createDatabase():

     global 
connconn.cursor()

     
# 创建表

     
c.execute('''CREATE TABLE IF NOT EXISTS [collect]([cid] INTEGER PRIMARY KEY,[curl] TEXT,[state] INTEGER DEFAULT '0',UNIQUE([curl]));''')

     
c.execute('''CREATE INDEX IF NOT EXISTS [collect_idx_state] ON [collect]([state]);''')

     
conn.commit()

     
c.close()


# 执行采集

def collect(url="http://answers.yahoo.com/"):

     global 
dl,headers0

     
print "GET:",url

     urls 
urlparse(url); path urls[2];

     if 
urls[4]!='' path += '?' urls[4]

     
dl.request(method="GET"url=pathheaders=headers); rs dl.getresponse()

     if 
rs.status==200 :

             
parseData(rs.read(),url)

     else :

             print 
"3 seconds, try again ..."time.sleep(3)

             
dl.request(method="GET"url=pathheaders=headers); rs dl.getresponse()

             if 
rs.status==200 :

                 
parseData(rs.read(),url)

             else :

                 print 
"3 seconds, try again ..."time.sleep(3)

                 
dl.request(method="GET"url=pathheaders=headers); rs dl.getresponse()

                 if 
rs.status==200 :

                     
parseData(rs.read(),url)

                 else :

                     print 
"Continue to collect ..."

                     
2

     
# 更新记录

     
updateOneUrl(url,R)

     
# 返回结果

     
return R


# 处理采集到的数据

def parseData(html,url):

     global 
dl,conn2;

     
conn.cursor()

     
# 格式化html代码

     
format formatURL(clearBlank(html),url)

     
# 取出所有的连接

     
urls re.findall(r'''(?iu)(<a[^>]*href="([^"]+)"[^>]*>)|(<a[^>]*href='([^']+)'[^>]*>)''',format)

     if urls != None :

             # 循环所有的连接

             for regs in urls :

                 # 得到一个单一的url

                 url = regs[1].strip()

                 # 判断url是否符合规则,符合,则插入数据库

                 if re.search('
http(.*)(/dir/index(.*)link=over(.*)|/question/index(.*))',url,re.I) != None :

                     if url[-11:]=='
link=mailto' : continue

                     try :

                             c.execute('''
INSERT INTO [collect]([curl])VALUES(?);''',(url,))

                             print "INSERT:",url

                     except sqlite.IntegrityError :

                             pass

             

     # 截取标题

     # title = sect(format,'
(<title>)','(</title>)')


     # 判断采集成功

     if True : R = 1

     

     conn.commit(); c.close()

     return R

     

# 取得一条URL

def getOneUrl(state=0):

     global conn; c = conn.cursor()

     c.execute('''
SELECT [curlFROM [collectWHERE [state]=? LIMIT 0,1;''',(state,))

     row = c.fetchone(); c.close()

     if row==None : return ""

     return row[0].encode('
utf-8')


# 更新一条记录的状态

def updateOneUrl(url,state):

     global conn; c = conn.cursor()

     c.execute('''
UPDATE [collectSET [state]=? WHERE [curl]=?;''',(state,url))

     conn.commit(); c.close()


# 清除html代码里的多余空格

def clearBlank(html):

     if len(html) == 0 : return ''

     html = re.sub('
r|n|t','',html)

     while html.find("     ")!=-1 or html.find('
&nbsp;')!=-1 :

             html = html.replace('
&nbsp;',' ').replace('     ',' ')

     return html


# 格式化url

def formatURL(html,url):

     urls = re.findall(r'''
(<a[^>]*href="([^"]+)"[^>]*>)|(<a[^>]*href='([^']+)'[^>]*>)''',html,re.I)

     if urls == None : return html

     for regs in urls :

             html = html.replace(regs[0],matchURL(regs[0],url))

     return html


# 格式化单个url

def matchURL(tag,url):

     urls = re.findall(r'''(.*)(src|href)=(.+?)( |\/>|>).*|(.*)url\(([^\)]+)\)''',tag,re.I)

     if urls == None :

             return tag

     else :

             if urls[0][5] == '' :

                 urlQuote = urls[0][2]

             else:

                 urlQuote = urls[0][5]


     if len(urlQuote) > 0 :

             cUrl = re.sub('''['"
]''','',urlQuote)

     else :

             return tag


     urls = urlparse(url); scheme = urls[0];

     if scheme!='' : scheme+='
://'

     
host urls[1]; host scheme host

     
if len(host)==: return tag

     path 
osp.dirname(urls[2]);

     if 
path=='/' path '';

     if 
cUrl.find("#")!=-cUrl cUrl[:cUrl.find("#")]

     
# 判断类型

     
if re.search(r'''^(http|https|ftp):(\/\/|\\\\)(([\w\/\\\+\-~`@:%])+\.)+([\w\/\\\.\=\?\+\-~`@':!%#]|(&amp;)|&)+''',cUrl,re.I) != None :

             # http开头的url类型要跳过

             
return tag

     elif cUrl
[:1] == '/' :

             
# 绝对路径

             
cUrl host cUrl

     elif cUrl
[:3]=='../' :

             
# 相对路径

             
while cUrl[:3]=='../' :

                 
cUrl cUrl[3:]

                 if 
len(path) > :

                     
path osp.dirname(path)

     
elif cUrl[:2]=='./' :

             
cUrl host path cUrl[1:]

     
elif cUrl.lower()[:7]=='mailto:' or cUrl.lower()[:11]=='javascript:' :

             return 
tag

     
else :

             
cUrl host path '/' cUrl

     R 
tag.replace(urlQuote,'"' cUrl '"')

     return 
R


# html代码截取函数

def sect(html,start,end):

     if 
len(html)==: return ;

     
# 正则表达式截取

     
if start[:1]==chr(40) and start[-1:]==chr(41) and end[:1]==chr(40) and end[-1:]==chr(41) :

             
reStart re.findall(r'(?isu)' start '(.*)' end,html)

             if 
reStart == None : return 

             
reStart[0][1]

     
# 字符串截取

     
else :

             
# 取得开始字符串的位置

             
intStart html.lower().find(start.lower())

             
# 如果搜索不到开始字符串,则直接返回空

             
if intStart == -: return 

             
# 取得结束字符串的位置

             
intEnd html[intStart+len(start):].lower().find(end.lower())

             
# 如果搜索不到结束字符串,也返回为空

             
if intEnd == -: return 

             
# 开始和结束字符串都有了,可以开始截取了

             
html[intStart+len(start):intStart+intEnd+len(start)]

     
# 返回截取的字符

     
return R


# ------------------------------------- 开始执行程序 -------------------------------------------


# 首先创建数据库

createDatabase()


# 开始采集

loops 0

while True:

     if 
loops>:

             
url getOneUrl()

             if 
url == "" :

                 
loops 0

             
else :

                 
loops collect(url)

     else :

             
loops collect()

     
# 暂停

     
time.sleep(sleep)

     if 
loops==: break

             

# 关闭HTTP连接

dl.close()

# 退出程序 

sys.exit()

Tags: python, 简易, 采集, 爬虫

« 上一篇 | 下一篇 »

只显示10条记录相关文章

MaxPHP 商业版 (浏览: 130, 评论: 0)
HMJ采集器1.4 下载 (Build 20060428). (浏览: 2460, 评论: 0)
EditorTools 无人值守采集助手1.4 (浏览: 2452, 评论: 0)

发表评论

评论内容 (必填):