#!/usr/bin/python

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

# 简易采集爬虫

#    1.采集Yahoo!Answers,parseData函数修改一下,可以采集任何网站

#    2.需要sqlite3或者pysqlite支持

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

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

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

#    6.采集Yahoo会被封IP数小时,所以这个采集用处不大

# Author: Lukin

# Date  : 2008-09-25

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

import re, sys, time

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 = 0

# 数据库路径

dbname = './database.db'

# 设置提交的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(dbname))

# 创建数据库

def createDatabase():

global conn,dbname;

if osp.isfile(osp.abspath(dbname)) : return

c = conn.cursor()

# 创建url列表存放表

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]);''')

# 创建分类表

c.execute('''CREATE TABLE IF NOT EXISTS [sorts]([sortid] INTEGER PRIMARY KEY,[sortname] TEXT,[sortpath] TEXT,[sortfoot] INTEGER DEFAULT '0',[sortnum] INTEGER DEFAULT '0',UNIQUE([sortpath]));''')

c.execute('''CREATE INDEX IF NOT EXISTS [sorts_idx_sortname] ON [sorts]([sortname]);''')

c.execute('''CREATE INDEX IF NOT EXISTS [sorts_idx_sortfoot] ON [sorts]([sortfoot]);''')

# 创建文章表

c.execute('''CREATE TABLE IF NOT EXISTS [article]([aid] INTEGER PRIMARY KEY,[sortid] INTEGER DEFAULT '0',[hits] INTEGER DEFAULT '0',[title] TEXT,[path] TEXT,[question] TEXT,[banswer] TEXT,[oanswer] TEXT,UNIQUE([path]));''')

c.execute('''CREATE INDEX IF NOT EXISTS [article_idx_sortid] ON [article]([sortid]);''')

# 事物提交

conn.commit()

c.close()

# 执行采集

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

global dl,error,headers; R = 0

print "GET:",url

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

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

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

if rs.status==200 :

R = parseData(rs.read(),url);

else :

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

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

if rs.status==200 :

R = parseData(rs.read(),url);

else :

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

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

if rs.status==200 :

R = parseData(rs.read(),url);

else :

print "Continue to collect ..."

R = 3

# 更新记录

updateOneUrl(url,R)

# 返回结果

return R

# 处理采集到的数据

def parseData(html,url):

global dl,conn; R = 2;

c = conn.cursor()

# 格式化html代码

format = formatURL(clearBlank(html),url)

# 取出所有的连接

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

if urls != None :

i = 0

# 循环所有的连接

for regs in urls :

# 得到一个单一的url

sUrl = en2chr(regs[1].strip())

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

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

if re.search('http(.*?)/dir/index(.*?)',sUrl,re.I) != None:

if sUrl.find('link=list') == -1 and sUrl.find('link=over') == -1 :

sUrl+= '&link=over'

else:

sUrl = sUrl.replace('link=list','link=over')

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

try :

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

i = i + 1

except sqlite.IntegrityError :

pass

if i>0 : print "Message: %d get a new URL." % (i,)

# 截取数据

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

sortfoot = 0

# 自动创建分类和分类关系

guide  = sect(format,'

  1. ','

','((.*?)Home(.*?))')

aGuide = re.findall(']*href="[^"]*"[^>]*>(.*?)',guide,re.I)

if aGuide != None :

sortname = ""

for sortname in aGuide :

sortname = sortname.strip()

sortpath = en2path(sortname)

# 查询分类是否存在

c.execute('SELECT [sortid],[sortname] FROM [sorts] WHERE [sortpath]=? LIMIT 0,1;',(sortpath,))

row = c.fetchone();

# 分类不存在,添加分类

if row==None :

c.execute('INSERT INTO [sorts]([sortname],[sortpath],[sortfoot])VALUES(?,?,?);',(sortname,sortpath,sortfoot))

sortfoot = c.lastrowid

else:

sortfoot = row[0]

# 标题

title = sect(format,'

','

')

# 最佳答案

BestAnswer = sect(format,'(

Best Answer(.*?)

(.*?)

)','(

)')

# 最佳答案不存在,则不采集

if BestAnswer != None :

# 文章路径

path = en2path(sortname + '-' + title.strip())

# 问题

adddata = sect(format,'

','

')

content = sect(format,'(

(.*?)

)','(

)')

if adddata != None : content += '
' + adddata

# 其他回答

OtherAnswer = ''

for regs in re.findall('

(.+?)

',format):

if regs.find('

') == -1 and regs.find('

') == -1 :

a1 = sect(regs,'

','

')

a2 = sect(regs,'

','

')

OtherAnswer+= '

' + a1

if a2 != None : OtherAnswer+= '

' + a2 + '

'

OtherAnswer+= '

'

# 判断采集成功

if title != None and content != None :

# 将数据写入到数据

try :

c.execute('INSERT INTO [article]([sortid],[title],[path],[question],[banswer],[oanswer])VALUES(?,?,?,?,?,?);',(sortfoot,title,path,content,BestAnswer,OtherAnswer))

print "Message:%s.html" % (path,)

R = 1

except sqlite.IntegrityError :

pass

# 提交写入数据库

conn.commit(); c.close()

return R

# 取得一条URL

def getOneUrl():

global conn; c = conn.cursor()

c.execute('SELECT [curl] FROM [collect] WHERE [state] IN(0,3) LIMIT 0,1;')

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 [collect] SET [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(' ')!=-1 :

html = html.replace(' ',' ').replace('  ',' ')

return html

# 格式化url

def formatURL(html,url):

urls = re.findall('''(]*?href="([^"]+)"[^>]*?>)|(]*?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('''(.*)(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)==0 : return tag

path = osp.dirname(urls[2]);

if path=='/' : path = '';

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

# 判断类型

if re.search('''^(http|https|ftp):(//|\\\\)(([\w/\\\+\-~`@:%])+\.)+([\w/\\\.\=\?\+\-~`@':!%#]|(&)|&)+''',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) > 0 :

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,cls=''):

if len(html)==0 : return ;

# 正则表达式截取

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

reHTML = re.search(start + '(.*?)' + end,html,re.I)

if reHTML == None : return

reHTML = reHTML.group()

intStart = re.search(start,reHTML,re.I).end()

intEnd = re.search(end,reHTML,re.I).start()

R = reHTML[intStart:intEnd]

# 字符串截取

else :

# 取得开始字符串的位置

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

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

if intStart == -1 : return

# 取得结束字符串的位置

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

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

if intEnd == -1 : return

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

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

# 清理内容

if cls != '' :

R = clear(R,cls)

# 返回截取的字符

return R

# 正则清除

def clear(html,regexs):

if regexs == '' : return html

for regex in regexs.split(chr(10)):

regex = regex.strip()

if regex != '' :

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

html = re.sub(regex,'',html,re.I|re.S)

else :

html = html.replace(regex,'')

return html

# 格式化为路径

def en2path(enStr):

return re.sub('[\W]+','-',en2chr(enStr),re.I|re.U).strip('-')

# 替换实体为正常字符

def en2chr(enStr):

return enStr.replace('&','&')

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

# 首先创建数据库

createDatabase()

# 开始采集

loops = 0

while True:

if loops>0 :

url = getOneUrl()

if url == "" :

loops = 0

else :

loops = collect(url)

else :

loops = collect()

# 暂停

time.sleep(sleep)

if loops==0 : break

# 关闭HTTP连接

dl.close()

# 退出程序

sys.exit()

python写采集程序_Python写的简易采集爬虫(蜘蛛)相关推荐

  1. python写窗体程序_python写窗口

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 最近在学习 pyqt5 gui 编程,大致路线是找了套网课<撩课-pyth ...

  2. python日历小程序_python写的日历小程序

    查看: 14785|回复: 262 [作品展示] python写的日历小程序 电梯直达 发表于 2013-8-19 21:38:32 | 只看该作者 |倒序浏览 |阅读模式 马上注册,结交更多好友,享 ...

  3. python数据可视化程序_python数据可视化简易版

    最近白天在整机器学习和算法导论,做预判分析的时候发现,经常用到几个画图代码,老是弄混.睡不着,深夜上线整理一波,顺便加强一下记忆叭.写多少是多少,不行就白天接着补.. 今天先整理一波常规画图操作.其实 ...

  4. python编写表白程序_python如何写出表白程序

    用python编表白程序的方法: 1.创建GUI窗口,实现代码的调用. 2.编写点击触发函数,实现表白程序. 具体代码如下: from tkinter import * from tkinter im ...

  5. python中怎么编写程序_python写完程序怎么运行

    安装并配置完成之后,我们就可以编写第一个python程序.学过其他语言的兄弟姐妹们,都知道语言的入门程序就是hello world.那么,我们这里也以hello world来抛砖引玉,打开python ...

  6. python红包程序_Python写随机发红包的原理流程

    首先来说说要用到的知识点,第一个要说的是扩展包random,random模块一般用来生成一个随机数 今天要用到ramdom中unifrom的方法用于生成一个指定范围的随机浮点数通过下面的图简单看下: ...

  7. python写了代码_Python写代码的用法建议

    1.Mutable and immutable types Python有两种内置或用户定义的类型 可变类型是允许就地修改内容的类型.典型的可变列表是列表和词典:所有列表都有变异方法,如 list.a ...

  8. python抢红包random实现_python写红包的原理流程包含random,lambda其中的使用和见简单介绍...

    Python写红包的原理流程 首先来说说要用到的知识点,第一个要说的是扩展包random,random模块一般用来生成一个随机数 今天要用到ramdom中unifrom的方法用于生成一个指定范围的随机 ...

  9. python写推箱子_python写的推箱子小游戏

    原标题:python写的推箱子小游戏 导语 Python 功能强大,可以写爬虫.服务器.数据分析.AI--当然,也可以写游戏. 用python写了个推箱子小游戏,在这里分享给大家,让我们愉快地开始吧~ ...

最新文章

  1. python中的函数、生成器的工作原理
  2. Java volatile关键字原理解剖
  3. 微服务网关Gateway实现Host过滤
  4. python多线程写同一文件_Python多线程写文件实例
  5. 在C ++ STL中使用string :: to_string()将数字转换为字符串
  6. 怎么看调用的接口_Hadoop RPC调用实例分析
  7. 常用的排序算法总结(三)
  8. 【Iterm2】如何解决iterm2窗口自动隐藏的问题
  9. python对数字进行简单的可逆加密_Python实现简单的可逆加密程序实例
  10. hnu小学期实训之数圈
  11. c编程:求出4#215;4矩阵中最大和最小元素值及其所在行下标和列下标,求出两条主对角线元素之和。...
  12. java caffe 验证码,监控Caffe的培训/验证过程
  13. Apache Flink 在斗鱼的应用与实践
  14. 深度学习软件资源列表
  15. Java面典_Java集合04——fail-fastfail-safe 详解
  16. Filezilla日文字符文件看不到或显示乱码的解决办法
  17. 很多人在Google Play商店购买或下载APP时出现问题,例如在你新安装的系统恢复APP或想要安装心愿单中的APP时,Play商店出现不能加载等错误,这实在是太烦人了。 所以,我通过搜索,把可
  18. 呼叫中心系统和外呼机器人的高效组合
  19. iPad闪屏跳动怎么回事?怎么解决?
  20. OKR工作法——宏观总结

热门文章

  1. C语言深度剖析笔记2
  2. 金仓数据库KingbaseES数据库参考手册(服务器配置参数14. 版本和平台兼容性)
  3. route和bridge是什么意思_路由器与网桥的区别是什么
  4. rabbitmq集群安装与配置(故障恢复)
  5. python中test的用法_Python基础介绍 | 使用pytest进行测试
  6. 中大计算机保研复试,过来人分享:平凡的我如何成功保研中山大学?
  7. V-rep 仿真与python远程控制
  8. 深入理解Android相机体系结构之二
  9. linux 模块 掉线重拨,arm中实现pppd连接GPRS上网的相关笔记,含GPRS自动拨号脚本(真正的实时监控,断线自动重拨)...
  10. 十年风雨,一个普通程序员的成长之路(五) 成长:得到与教训