python实现爬虫统计学校bbs男女比例之多线程爬虫(二)

接着第一篇继续学习。

一、数据分类

正确数据:id、性别、活动时间三者都有

放在这个文件里file1 = ‘ruisi\\correct%s-%s.txt’ % (startnum, endnum)

数据格式为293001 男 2015-5-1 19:17

没有时间:有id、有性别,无活动时间

放这个文件里file2 = ‘ruisi\\errtime%s-%s.txt’ % (startnum, endnum)

数据格式为2566 女 notime

用户不存在:该id没有对应的用户

放这个文件里file3 = ‘ruisi\\notexist%s-%s.txt’ % (startnum, endnum)

数据格式为29005 notexist

未知性别:有id,但是性别从网页上无法得知(经检查,这种情况也没有活动时间)

放这个文件里 file4 = ‘ruisi\\unkownsex%s-%s.txt’ % (startnum, endnum)

数据格式 221794 unkownsex

网络错误:网断了,或者服务器故障,需要对这些id重新检查

放这个文件里 file5 = ‘ruisi\\httperror%s-%s.txt’ % (startnum, endnum)

数据格式 271004 httperror

如何不间断得爬虫信息

本项目有一个考虑:是不间断爬取信息,如果因为断网、bbs服务器故障啥的,我的爬虫程序就退出的话。那我们还得从间断的地方继续爬,或者更麻烦的是从头开始爬。
所以,我采取的方法是,如果遇到故障,就把这些异常的id记录下来。等一次遍历之后,才对这些异常的id进行重新爬取性别。
本文系列(一)给出了一个 getinfo(myurl, seword),通过给定链接和给定正则表达式爬取信息。
这个函数可以用来查看性别的最后活动时间信息。
我们再定义一个安全的爬取函数,不会间断程序运行的,这儿用到try except异常处理。

这儿代码试了两次getinfo(myurl, seword),如果第2次还是抛出异常了,就把这个id保存在file5里面
如果能获取到信息,就返回信息

file5 = ‘ruisi\\httperror%s-%s.txt’ % (startnum, endnum)
def safeget(myid, myurl, seword):
try:
return getinfo(myurl, seword)
except:
try:
return getinfo(myurl, seword)
except:
httperrorfile = open(file5, ‘a’)
info = ‘%d %s\n’ % (myid, ‘httperror’)
httperrorfile.write(info)
httperrorfile.close()
return ‘httperror’

依次遍历,获取id从[1,300,000]的用户信息

我们定义一个函数,这儿的思路是获取sex和time,如果有sex,进而继续判断是否有time;如果没sex,判断是否这个用户不存在还是性别无法爬取。

其中要考虑到断网或者bbs服务器故障的情况。

url1 = ‘http://rs.xidian.edu.cn/home.php?mod=space&u
url2 = ‘http://rs.xidian.edu.cn/home.php?mod=space&u
def searchweb(idarr):
for id in idarr:
sexurl = url1 % (id) #将%s替换为id
timeurl = url2 % (id)
sex = safeget(id,sexurl, sexre)
if not sex: #如果sexurl里面找不到性别,在timeurl再尝试找一下
sex = safeget(id,timeurl, sexre)
time = safeget(id,timeurl, timere)
#如果出现了httperror,需要重新爬取
if (sex is ‘httperror’) or (time is ‘httperror’) :
pass
else:
if sex:
info = ‘%d %s’ % (id, sex)
if time:
info = ‘%s %s\n’ % (info, time)
wfile = open(file1, ‘a’)
wfile.write(info)
wfile.close()
else:
info = ‘%s %s\n’ % (info, ‘notime’)
errtimefile = open(file2, ‘a’)
errtimefile.write(info)
errtimefile.close()
else:
#这儿是性别是none,然后确定一下是不是用户不存在
#断网的时候加上这个,会导致4个重复httperror
#可能用户的性别我们无法知道,他没有填写
notexist = safeget(id,sexurl, notexistre)
if notexist is ‘httperror’:
pass
else:
if notexist:
notexistfile = open(file3, ‘a’)
info = ‘%d %s\n’ % (id, ‘notexist’)
notexistfile.write(info)
notexistfile.close()
else:
unkownsexfile = open(file4, ‘a’)
info = ‘%d %s\n’ % (id, ‘unkownsex’)
unkownsexfile.write(info)
unkownsexfile.close()

这儿后期检查发现了一个问题

sex = safeget(id,sexurl, sexre)
if not sex:
sex = safeget(id,timeurl, sexre)
time = safeget(id,timeurl, timere)

这个代码如果断网的时候,调用了3次safeget,每次调用都会往文本里面同一个id写多次httperror

251538 httperror
251538 httperror
251538 httperror
251538 httperror

多线程爬取信息?

数据统计可以用多线程,因为是独立的多个文本
1、popen介绍

使用popen可以自定义标准输入、标准输出和标准错误输出。我在sap实习的时候,项目组在linux平台下经常使用popen,可能是因为可以方便重定向输出。

下面这段代码借鉴了以前项目组的实现方法,popen可以调用系统cmd命令。下面3个communicate()连在一起表示要等这3个线程都结束。

疑惑?
试验了一下,必须3个communicate()紧挨着才能保证3个线程同时开启,最后等待3个线程都结束。

p1=popen([‘python’, ‘ruisi.py’, str(s0),str(s1)],bufsize=10000, stdout=subprocess.pipe)
p2=popen([‘python’, ‘ruisi.py’, str(s1),str(s2)],bufsize=10000, stdout=subprocess.pipe)
p3=popen([‘python’, ‘ruisi.py’, str(s2),str(s3)],bufsize=10000, stdout=subprocess.pipe)
p1.communicate()
p2.communicate()
p3.communicate()

2、定义一个单线程的爬虫

用法:python ruisi.py

这段代码就是爬取[startnum, endnum)信息,输出到相应的文本里。它是一个单线程的程序,若要实现多线程的话,在外部调用它的地方实现多线程。

# ruisi.py
# coding=utf-8
import urllib2, re, sys, threading, time,thread
# myurl as 指定链接
# seword as 正则表达式,用unicode表示
# 返回根据正则表达式匹配的信息或者none
def getinfo(myurl, seword):
headers = {
‘user-agent’: ‘mozilla/5.0 (windows; u; windows nt 6.1; en-us; rv:1.9.1.6) gecko/20091201 firefox/3.5.6’
}
req = urllib2.request(
url=myurl,
headers=headers
)
time.sleep(0.3)
response = urllib2.urlopen(req)
html = response.read()
html = unicode(html, ‘utf-8’)
timematch = seword.search(html)
if timematch:
s = timematch.groups()
return s[0]
else:
return none
#尝试两次getinfo()
#第2次失败后,就把这个id标记为httperror
def safeget(myid, myurl, seword):
try:
return getinfo(myurl, seword)
except:
try:
return getinfo(myurl, seword)
except:
httperrorfile = open(file5, ‘a’)
info = ‘%d %s\n’ % (myid, ‘httperror’)
httperrorfile.write(info)
httperrorfile.close()
return ‘httperror’
#输出一个 idarr 范围,比如[1,1001)
def searchweb(idarr):
for id in idarr:
sexurl = url1 % (id)
timeurl = url2 % (id)
sex = safeget(id,sexurl, sexre)
if not sex:
sex = safeget(id,timeurl, sexre)
time = safeget(id,timeurl, timere)
if (sex is ‘httperror’) or (time is ‘httperror’) :
pass
else:
if sex:
info = ‘%d %s’ % (id, sex)
if time:
info = ‘%s %s\n’ % (info, time)
wfile = open(file1, ‘a’)
wfile.write(info)
wfile.close()
else:
info = ‘%s %s\n’ % (info, ‘notime’)
errtimefile = open(file2, ‘a’)
errtimefile.write(info)
errtimefile.close()
else:
notexist = safeget(id,sexurl, notexistre)
if notexist is ‘httperror’:
pass
else:
if notexist:
notexistfile = open(file3, ‘a’)
info = ‘%d %s\n’ % (id, ‘notexist’)
notexistfile.write(info)
notexistfile.close()
else:
unkownsexfile = open(file4, ‘a’)
info = ‘%d %s\n’ % (id, ‘unkownsex’)
unkownsexfile.write(info)
unkownsexfile.close()
def main():
reload(sys)
sys.setdefaultencoding(‘utf-8’)
if len(sys.argv) != 3:
print ‘usage: python ruisi.py ‘
sys.exit(-1)
global sexre,timere,notexistre,url1,url2,file1,file2,file3,file4,startnum,endnum,file5
startnum=int(sys.argv[1])
endnum=int(sys.argv[2])
sexre = re.compile(u’em>\u6027\u522b(.*?)\u4e0a\u6b21\u6d3b\u52a8\u65f6\u95f4(.*?))\u62b1\u6b49\uff0c\u60a8\u6307\u5b9a\u7684\u7528\u6237\u7a7a\u95f4\u4e0d\u5b58\u5728

Posted in 未分类

发表评论