前言

自己实现的Python 爬虫,目的是统计学校论坛上男女用户各占多少。
转载请注明出处,文章地址如下

  • python实现爬虫统计学校BBS男女比例(一)前期准备、方案分析
    http://blog.csdn.net/never_cxb/article/details/49934003
  • python实现爬虫统计学校BBS男女比例(二)多线程爬虫
    http://blog.csdn.net/never_cxb/article/details/49934961
  • python实现爬虫统计学校BBS男女比例(三)数据处理
    http://blog.csdn.net/never_cxb/article/details/49993353

数据分析

得到了以下列字符串开头的文本数据,我们需要进行处理

名称 特性
correct 此id的性别、活动时间都存在
errTime 此id的性别有,活动时间无 (改成noTime可能更好)
unkownsex 此id的性别无法得知
notexist 此id不存在相应用户
httperror 此id由于服务器故障,需要回滚处理

回滚

我们需要对httperror的数据进行再处理

因为代码的原因,具体可见本系列文章(二),会导致文本里面同一个id连续出现几次httperror记录:

//httperror265001_266001.txt
265002 httperror
265002 httperror
265002 httperror
265002 httperror
265003 httperror
265003 httperror
265003 httperror
265003 httperror

所以我们在代码里要考虑这种情形,不能每一行的id都进行处理,是判断是否重复的id。

java里面有缓存方法可以避免频繁读取硬盘上的文件,python其实也有,可以见这篇文章。

def main():reload(sys)sys.setdefaultencoding('utf-8')global sexRe,timeRe,notexistRe,url1,url2,file1,file2,file3,file4,startNum,endNum,file5sexRe = re.compile(u'em>\u6027\u522b</em>(.*?)</li')timeRe = re.compile(u'em>\u4e0a\u6b21\u6d3b\u52a8\u65f6\u95f4</em>(.*?)</li')notexistRe = re.compile(u'(p>)\u62b1\u6b49\uff0c\u60a8\u6307\u5b9a\u7684\u7528\u6237\u7a7a\u95f4\u4e0d\u5b58\u5728<')url1 = 'http://rs.xidian.edu.cn/home.php?mod=space&uid=%s'url2 = 'http://rs.xidian.edu.cn/home.php?mod=space&uid=%s&do=profile'file1 = 'ruisi\\correct_re.txt'file2 = 'ruisi\\errTime_re.txt'file3 = 'ruisi\\notexist_re.txt'file4 = 'ruisi\\unkownsex_re.txt'file5 = 'ruisi\\httperror_re.txt'#遍历文件夹里面以httperror开头的文本for filename in os.listdir(r'E:\pythonProject\ruisi'):if filename.startswith('httperror'):count = 0newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)readFile = open(newName,'r')oldLine = '0'for line in readFile:#newLine 用来比较是否是重复的idnewLine =  lineif (newLine != oldLine):nu = newLine.split()[0]oldLine = newLinecount += 1searchWeb((int(nu),))print "%s deal %s lines" %(filename, count)

本代码为了简便,没有再把httperror的那些id分类,直接存储为下面这5个文件里

    file1 = 'ruisi\\correct_re.txt'file2 = 'ruisi\\errTime_re.txt'file3 = 'ruisi\\notexist_re.txt'file4 = 'ruisi\\unkownsex_re.txt'file5 = 'ruisi\\httperror_re.txt'

可以看下输出Log记录,总共处理了多少个httperror的数据。

"D:\Program Files\Python27\python.exe" E:/pythonProject/webCrawler/reload.py
httperror132001-133001.txt deal 21 lines
httperror2001-3001.txt deal 4 lines
httperror251001-252001.txt deal 5 lines
httperror254001-255001.txt deal 1 lines

单线程统计 unkownsex 数据

代码简单,我们利用单线程统计一下unkownsex(由于权限原因无法获取、或者该用户没有填写)的用户。另外,经过我们检查,没有性别的用户也是没有活动时间的。

数据格式如下:

253042 unkownsex
253087 unkownsex
253102 unkownsex
253118 unkownsex
253125 unkownsex
253136 unkownsex
253161 unkownsex
import os,time
sumCount = 0startTime = time.clock()for filename in os.listdir(r'E:\pythonProject\ruisi'):if filename.startswith('unkownsex'):count = 0newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)readFile = open(newName,'r')for line in open(newName):count += 1sumCount +=1print "%s deal %s lines" %(filename, count)
print '%s unkowns sex' %(sumCount)endTime = time.clock()
print "cost time " + str(endTime - startTime) + " s"

处理速度很快,输出如下:

unkownsex1-1001.txt deal 204 lines
unkownsex100001-101001.txt deal 50 lines
unkownsex10001-11001.txt deal 206 lines
#...省略中间输出信息
unkownsex99001-100001.txt deal 56 lines
unkownsex_re.txt deal 1085 lines
14223 unkowns sex
cost time 0.0813142301261 s

单线程统计 correct 数据

数据格式如下:

31024 男 2014-11-11 13:20
31283 男 2013-3-25 19:41
31340 保密 2015-2-2 15:17
31427 保密 2014-8-10 09:17
31475 保密 2013-7-2 08:59
31554 保密 2014-10-17 17:02
31621 男 2015-5-16 19:27
31872 保密 2015-1-11 16:49
31915 保密 2014-5-4 11:01
31997 保密 2015-5-16 20:14

代码如下,实现思路就是一行一行读取,利用line.split()获取性别信息。sumCount 是统计一个多少人,boycount 、girlcount 、secretcount 分别统计男、女、保密的人数。我们还是利用unicode进行正则匹配。

import os,sys,time
reload(sys)
sys.setdefaultencoding('utf-8')
startTime = time.clock()
sumCount = 0
boycount = 0
girlcount = 0
secretcount = 0
for filename in os.listdir(r'E:\pythonProject\ruisi'):if filename.startswith('correct'):newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)readFile = open(newName,'r')for line in readFile:sexInfo = line.split()[1]sumCount +=1if sexInfo == u'\u7537' :boycount += 1elif sexInfo == u'\u5973':girlcount +=1elif sexInfo == u'\u4fdd\u5bc6':secretcount +=1print "until %s, sum is %s boys; %s girls; %s secret;" %(filename, boycount,girlcount,secretcount)
print "total is %s;  %s boys; %s girls; %s secret;" %(sumCount, boycount,girlcount,secretcount)
endTime = time.clock()
print "cost time " + str(endTime - startTime) + " s"

注意,我们输出的是截止某个文件的统计信息,而不是单个文件的统计情况。输出结果如下:

until correct1-1001.txt, sum is 110 boys; 7 girls; 414 secret;
until correct100001-101001.txt, sum is 125 boys; 13 girls; 542 secret;
#...省略
until correct99001-100001.txt, sum is 11070 boys; 3113 girls; 26636 secret;
until correct_re.txt, sum is 13937 boys; 4007 girls; 28941 secret;
total is 46885;  13937 boys; 4007 girls; 28941 secret;
cost time 3.60047888495 s

多线程统计数据

为了更快统计,我们可以利用多线程。
作为对比,我们试下单线程需要的时间。

# encoding: UTF-8
import threading
import time,os,sys#全局变量
SUM = 0
BOY = 0
GIRL = 0
SECRET = 0
NUM =0#本来继承自threading.Thread,覆盖run()方法,用start()启动线程
#这和java里面很像
class StaFileList(threading.Thread):#文本名称列表fileList = []def __init__(self, fileList):threading.Thread.__init__(self)self.fileList = fileListdef run(self):global SUM, BOY, GIRL, SECRET#可以加上个耗时时间,这样多线程更加明显,而不是顺序的thread-1,2,3#time.sleep(1)#acquire获取锁if mutex.acquire(1):self.staFiles(self.fileList)#release释放锁mutex.release()#处理输入的files列表,统计男女人数#注意这儿数据同步问题,global使用全局变量def staFiles(self, files):global SUM, BOY, GIRL, SECRETfor name in  files:newName = 'E:\\pythonProject\\ruisi\\%s' % (name)readFile = open(newName,'r')for line in readFile:sexInfo = line.split()[1]SUM +=1if sexInfo == u'\u7537' :BOY += 1elif sexInfo == u'\u5973':GIRL +=1elif sexInfo == u'\u4fdd\u5bc6':SECRET +=1# print "thread %s, until %s, total is %s; %s boys; %s girls;" \#       " %s secret;" %(self.name, name, SUM, BOY,GIRL,SECRET)def test():#files保存多个文件,可以设定一个线程处理多少个文件files = []#用来保存所有的线程,方便最后主线程等待所以子线程结束staThreads = []i = 0for filename in os.listdir(r'E:\pythonProject\ruisi'):#没获取10个文本,就创建一个线程if filename.startswith('correct'):files.append(filename)i+=1#一个线程处理20个文件if i == 20 :staThreads.append(StaFileList(files))files = []i = 0#最后剩余的files,很可能长度不足10个if files:staThreads.append(StaFileList(files))for t in staThreads:t.start()# 主线程中等待所有子线程退出,如果不加这个,速度更快些?for t in staThreads:t.join()if __name__ == '__main__':reload(sys)sys.setdefaultencoding('utf-8')startTime = time.clock()mutex = threading.Lock()test()print "Multi Thread, total is %s;  %s boys; %s girls; %s secret;" %(SUM, BOY,GIRL,SECRET)endTime = time.clock()print "cost time " + str(endTime - startTime) + " s"

输出

Multi Thread, total is 46885;  13937 boys; 4007 girls; 28941 secret;
cost time 0.132137192794 s

我们发现时间和单线程差不多。因为这儿涉及到线程同步问题,获取锁和释放锁都是需要时间开销的,线程间切换保存中断和恢复中断也都是需要时间开销的。

较多数据的单线程和多线程对比

我们可以对correct、errTime 、unkownsex的文本都进行处理。
单线程代码

# coding=utf-8
import os,sys,time
reload(sys)
sys.setdefaultencoding('utf-8')
startTime = time.clock()
sumCount = 0
boycount = 0
girlcount = 0
secretcount = 0
unkowncount = 0
for filename in os.listdir(r'E:\pythonProject\ruisi'):# 有性别、活动时间if filename.startswith('correct') :newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)readFile = open(newName,'r')for line in readFile:sexInfo =line.split()[1]sumCount +=1if sexInfo == u'\u7537' :boycount += 1elif sexInfo == u'\u5973':girlcount +=1elif sexInfo == u'\u4fdd\u5bc6':secretcount +=1# print "until %s, sum is %s boys; %s girls; %s secret;" %(filename, boycount,girlcount,secretcount)#没有活动时间,但是有性别elif filename.startswith("errTime"):newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)readFile = open(newName,'r')for line in readFile:sexInfo =line.split()[1]sumCount +=1if sexInfo == u'\u7537' :boycount += 1elif sexInfo == u'\u5973':girlcount +=1elif sexInfo == u'\u4fdd\u5bc6':secretcount +=1# print "until %s, sum is %s boys; %s girls; %s secret;" %(filename, boycount,girlcount,secretcount)#没有性别,也没有时间,直接统计行数elif filename.startswith("unkownsex"):newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)# count = len(open(newName,'rU').readlines())#对于大文件用循环方法,count 初始值为 -1 是为了应对空行的情况,最后+1得到0行count = -1for count, line in enumerate(open(newName, 'rU')):passcount += 1unkowncount += countsumCount += count# print "until %s, sum is %s unkownsex" %(filename, unkowncount)print "Single Thread, total is %s;  %s boys; %s girls; %s secret; %s unkownsex;" %(sumCount, boycount,girlcount,secretcount,unkowncount)
endTime = time.clock()
print "cost time " + str(endTime - startTime) + " s"

输出为

Single Thread, total is 61111;  13937 boys; 4009 girls; 28942 secret; 14223 unkownsex;
cost time 1.37444645628 s

多线程代码

__author__ = 'admin'
# encoding: UTF-8
#多线程处理程序
import threading
import time,os,sys#全局变量
SUM = 0
BOY = 0
GIRL = 0
SECRET = 0
UNKOWN = 0class StaFileList(threading.Thread):#文本名称列表fileList = []def __init__(self, fileList):threading.Thread.__init__(self)self.fileList = fileListdef run(self):global SUM, BOY, GIRL, SECRETif mutex.acquire(1):self.staManyFiles(self.fileList)mutex.release()#处理输入的files列表,统计男女人数#注意这儿数据同步问题def staCorrectFiles(self, files):global SUM, BOY, GIRL, SECRETfor name in  files:newName = 'E:\\pythonProject\\ruisi\\%s' % (name)readFile = open(newName,'r')for line in readFile:sexInfo = line.split()[1]SUM +=1if sexInfo == u'\u7537' :BOY += 1elif sexInfo == u'\u5973':GIRL +=1elif sexInfo == u'\u4fdd\u5bc6':SECRET +=1# print "thread %s, until %s, total is %s; %s boys; %s girls;" \#       " %s secret;" %(self.name, name, SUM, BOY,GIRL,SECRET)def staManyFiles(self, files):global SUM, BOY, GIRL, SECRET,UNKOWNfor name in  files:if name.startswith('correct') :newName = 'E:\\pythonProject\\ruisi\\%s' % (name)readFile = open(newName,'r')for line in readFile:sexInfo = line.split()[1]SUM +=1if sexInfo == u'\u7537' :BOY += 1elif sexInfo == u'\u5973':GIRL +=1elif sexInfo == u'\u4fdd\u5bc6':SECRET +=1# print "thread %s, until %s, total is %s; %s boys; %s girls;" \#       " %s secret;" %(self.name, name, SUM, BOY,GIRL,SECRET)#没有活动时间,但是有性别elif name.startswith("errTime"):newName = 'E:\\pythonProject\\ruisi\\%s' % (name)readFile = open(newName,'r')for line in readFile:sexInfo = line.split()[1]SUM +=1if sexInfo == u'\u7537' :BOY += 1elif sexInfo == u'\u5973':GIRL +=1elif sexInfo == u'\u4fdd\u5bc6':SECRET +=1# print "thread %s, until %s, total is %s; %s boys; %s girls;" \#       " %s secret;" %(self.name, name, SUM, BOY,GIRL,SECRET)#没有性别,也没有时间,直接统计行数elif name.startswith("unkownsex"):newName = 'E:\\pythonProject\\ruisi\\%s' % (name)# count = len(open(newName,'rU').readlines())#对于大文件用循环方法,count 初始值为 -1 是为了应对空行的情况,最后+1得到0行count = -1for count, line in enumerate(open(newName, 'rU')):passcount += 1UNKOWN += countSUM += count# print "thread %s, until %s, total is %s; %s unkownsex" %(self.name, name, SUM, UNKOWN)def test():files = []#用来保存所有的线程,方便最后主线程等待所以子线程结束staThreads = []i = 0for filename in os.listdir(r'E:\pythonProject\ruisi'):#没获取10个文本,就创建一个线程if filename.startswith("correct") or filename.startswith("errTime")  or filename.startswith("unkownsex"):files.append(filename)i+=1if i == 20 :staThreads.append(StaFileList(files))files = []i = 0#最后剩余的files,很可能长度不足10个if files:staThreads.append(StaFileList(files))for t in staThreads:t.start()# 主线程中等待所有子线程退出for t in staThreads:t.join()if __name__ == '__main__':reload(sys)sys.setdefaultencoding('utf-8')startTime = time.clock()mutex = threading.Lock()test()print "Multi Thread, total is %s;  %s boys; %s girls; %s secret; %s unkownsex" %(SUM, BOY,GIRL,SECRET,UNKOWN)endTime = time.clock()print "cost time " + str(endTime - startTime) + " s"endTime = time.clock()print "cost time " + str(endTime - startTime) + " s"

输出为

Multi Thread, total is 61111;  13937 boys; 4009 girls; 28942 secret;
cost time 1.23049112201 s

可以看出多线程还是优于单线程的,由于使用的同步,数据统计是一直的。

总结思考

注意python在类内部经常需要加上self,这点和java区别很大。

    def __init__(self, fileList):threading.Thread.__init__(self)self.fileList = fileListdef run(self):global SUM, BOY, GIRL, SECRETif mutex.acquire(1):#调用类内部方法需要加selfself.staFiles(self.fileList)mutex.release()

参考文章

python多线程编程(3): 使用互斥锁同步线程

total is 61111;  13937 boys; 4009 girls; 28942 secret; 14223 unkownsex;
cost time 1.25413238673 s

python实现爬虫统计学校BBS男女比例(三)数据处理相关推荐

  1. python分别统计男女人数_python实现爬虫统计学校BBS男女比例(一),python男女比例...

    python实现爬虫统计学校BBS男女比例(一),python男女比例 一.项目需求 前言:BBS上每个id对应一个用户,他们注册时候会填写性别(男.女.保密三选一). 经过检查,BBS注册用户的id ...

  2. python分别统计男女人数_python实现爬虫统计学校BBS男女比例(一)

    一.项目需求 前言:BBS上每个id对应一个用户,他们注册时候会填写性别(男.女.保密三选一). 经过检查,BBS注册用户的id对应1-300000,大概是30万的用户 笔者想用Python统计BBS ...

  3. 利用Python统计微信联系人男女比例以及简单的地区分布

    寒暄的话不多说,直接进入主题. 运行效果图: [准备环境] Python版本:v3.5及其以上 开发工具:随意,此处使用Pycharm [依赖包] 1.itchat (CMD运行:pip instal ...

  4. python小爬虫—获取学校教务处成绩

    开始想自己计算一下绩点,所以第一个小爬虫就从抓取自己成绩开始 1.工具: chrome浏览器 vscode 2.先来分析一下学校教务处成绩管理系统的结构,用的竟然是frame标签!!首先是一个输入学号 ...

  5. python学会爬虫要多久_零基础三天学会Python爬虫(第二天)

    一.Python与urllib2 现在已经迫不及待的想尝试一下url和网络爬虫的配合关系了.我们上一届已经介绍过了,爬虫就是把URL地址中的网络资源读取出来,然后处理(保存到本地,或者打印等等).本篇 ...

  6. python字典统计男女比例_python统计男女比例-女性时尚流行美容健康娱乐mv-ida网...

    女性时尚流行美容健康娱乐mv-ida网 mvida时尚娱乐网 首页 美容 护肤 化妆技巧 发型 服饰 健康 情感 美体 美食 娱乐 明星八卦 首页  > 高级搜索 python 实现代码行数 统 ...

  7. python爬取国家男女比例_如何利用Python网络爬虫抓取微信好友数量以及微信好友的男女比例?...

    这个实现起来很简单,微信专门给python提供了一个接口包itchat,我们可以通过这个接口获取微信好友信息,继而统计好友数量和男女比例,下面我大概介绍一下实现过程及主要代码,实验环境win7+pyt ...

  8. 北京理工大学 计算机学院男女比例,39所985高校男女比例排名,看看哪些学校比例严重失调!...

    39所985高校重排,不过这次不是拼实力,而是拼男女比例.看看哪些学校女生都是稀有动物,哪些学校光棍最多. 第一档,男生比例30%-40%. No.39:中央民族大学:男生比例30% 中央民族大学绝对 ...

  9. 渭南师范计算机学院男女比例,全国高校男女比例大揭秘!去这些大学怕是要单身四年了...

    原标题:全国高校男女比例大揭秘!去这些大学怕是要单身四年了 希望每天收到我们的文章吗,点上面蓝色文字"语文日刊"关注就可以. 更多初中内容,请关注:初中试题库大(stkuda) 给 ...

最新文章

  1. shell 获取文件最后一行
  2. 观点 | 云原生时代来袭 下一代云数据库技术将走向何方?
  3. jQuery.理解选取更新范围
  4. linux关机_LINUX快速入门第二章:Linux 系统启动过程
  5. android ExpandableListView详解
  6. ETL学习之八:添加日志记录
  7. 为什么grab显示无法定位_西门子SIPARTPS2阀门定位器的故障处理
  8. 手机html5顶部返回上一页,手机端网页返回顶部js代码
  9. 博图安装msi失败_西门子软件WIN7系统安装须知
  10. 用php计算身体质量指数,BMI计算器,身体质量指数BMI在线计算
  11. OpenGL 与显卡
  12. 混合高斯模型介绍以及应用
  13. GetLastError 返回值意义
  14. tablepc是什么平板电脑_平板电脑是什么
  15. 什么是阿里云Intel Xeon(Ice Lake) Platinum 8369B服务器?
  16. Vimeo上传功能中的SSRF
  17. Python 图像中颜色替换
  18. java基于Springboot的幼儿园管理系统-计算机毕业设计
  19. 关于多标签分类任务的损失函数和评价指标的一点理解
  20. 【Tools】Win10 OBS录视频黑屏问题

热门文章

  1. 利用javascript实现表格数据自动从剪贴板录入
  2. 三种算法求解最大公约数和最小公倍数
  3. Attributed Graph Clustering: A Deep Attentional Embedding Approach,IJCAI2019
  4. op积分上反馈电阻 作用 理解 op 积分
  5. IAR Embedded Workbench 将支持 RISC-V 太空级处理器 NOEL-V
  6. 关闭阿里云的短信提醒
  7. oracle大数据量查询超时排查
  8. 【愚公系列】2022年08月 微信小程序-(rich-text)富文本和(text)文本的详解
  9. python爬虫与java爬虫的区别_java爬虫(一)主流爬虫框架的基本介绍
  10. 报错:启动apache服务时出现报错