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


Posted in Python onDecember 31, 2015

本文主要介绍了数据处理方面的内容,希望大家仔细阅读。

一、数据分析

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

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

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

二、回滚

我们需要对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,file5
  sexRe = 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 = 0
      newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)
      readFile = open(newName,'r')
      oldLine = '0'
      for line in readFile:
        #newLine 用来比较是否是重复的id
        newLine = line
        if (newLine != oldLine):
          nu = newLine.split()[0]
          oldLine = newLine
          count += 1
          searchWeb((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 = 0

startTime = time.clock()

for filename in os.listdir(r'E:\pythonProject\ruisi'):
  if filename.startswith('unkownsex'):
    count = 0
    newName = 'E:\\pythonProject\\ruisi\\%s' % (filename)
    readFile = open(newName,'r')
    for line in open(newName):
      count += 1
      sumCount +=1
    print "%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 +=1
      if sexInfo == u'\u7537' :
        boycount += 1
      elif sexInfo == u'\u5973':
        girlcount +=1
      elif sexInfo == u'\u4fdd\u5bc6':
        secretcount +=1
    print "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 = fileList

  def 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, SECRET
    for name in files:
      newName = 'E:\\pythonProject\\ruisi\\%s' % (name)
      readFile = open(newName,'r')
      for line in readFile:
        sexInfo = line.split()[1]
        SUM +=1
        if sexInfo == u'\u7537' :
          BOY += 1
        elif sexInfo == u'\u5973':
          GIRL +=1
        elif 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 = 0
  for 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 +=1
      if sexInfo == u'\u7537' :
        boycount += 1
      elif sexInfo == u'\u5973':
        girlcount +=1
      elif 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 +=1
      if sexInfo == u'\u7537' :
        boycount += 1
      elif sexInfo == u'\u5973':
        girlcount +=1
      elif 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 = -1
    for count, line in enumerate(open(newName, 'rU')):
      pass
    count += 1
    unkowncount += count
    sumCount += 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 = 0

class StaFileList(threading.Thread):
  #文本名称列表
  fileList = []

  def __init__(self, fileList):
    threading.Thread.__init__(self)
    self.fileList = fileList

  def run(self):
    global SUM, BOY, GIRL, SECRET
    if mutex.acquire(1):
      self.staManyFiles(self.fileList)
      mutex.release()

  #处理输入的files列表,统计男女人数
  #注意这儿数据同步问题
  def staCorrectFiles(self, files):
    global SUM, BOY, GIRL, SECRET
    for name in files:
      newName = 'E:\\pythonProject\\ruisi\\%s' % (name)
      readFile = open(newName,'r')
      for line in readFile:
        sexInfo = line.split()[1]
        SUM +=1
        if sexInfo == u'\u7537' :
          BOY += 1
        elif sexInfo == u'\u5973':
          GIRL +=1
        elif 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,UNKOWN
    for 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 +=1
          if sexInfo == u'\u7537' :
            BOY += 1
          elif sexInfo == u'\u5973':
            GIRL +=1
          elif 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 +=1
          if sexInfo == u'\u7537' :
            BOY += 1
          elif sexInfo == u'\u5973':
            GIRL +=1
          elif 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 = -1
        for count, line in enumerate(open(newName, 'rU')):
          pass
        count += 1
        UNKOWN += count
        SUM += count
        # print "thread %s, until %s, total is %s; %s unkownsex" %(self.name, name, SUM, UNKOWN)


def test():
  files = []
  #用来保存所有的线程,方便最后主线程等待所以子线程结束
  staThreads = []
  i = 0
  for 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+=1
      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; %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 = fileList

  def run(self):
    global SUM, BOY, GIRL, SECRET
    if mutex.acquire(1):
      #调用类内部方法需要加self
      self.staFiles(self.fileList)
      mutex.release()

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

以上就是本文的全部内容,希望对大家的学习有所帮助。

Python 相关文章推荐
python 简易计算器程序,代码就几行
Aug 29 Python
python encode和decode的妙用
Sep 02 Python
Python实现的石头剪子布代码分享
Aug 22 Python
Pyqt实现无边框窗口拖动以及窗口大小改变
Apr 19 Python
python实现爬取图书封面
Jul 05 Python
django session完成状态保持的方法
Nov 27 Python
解决Python pandas plot输出图形中显示中文乱码问题
Dec 12 Python
对python多线程中Lock()与RLock()锁详解
Jan 11 Python
简单了解python高阶函数map/reduce
Jun 28 Python
Python使用matplotlib 画矩形的三种方式分析
Oct 31 Python
给keras层命名,并提取中间层输出值,保存到文档的实例
May 23 Python
python两个list[]相加的实现方法
Sep 23 Python
python实现爬虫统计学校BBS男女比例之多线程爬虫(二)
Dec 31 #Python
python实现爬虫统计学校BBS男女比例(一)
Dec 31 #Python
Python 功能和特点(新手必学)
Dec 30 #Python
python实现文本文件合并
Dec 29 #Python
Python验证码识别处理实例
Dec 28 #Python
在Windows系统上搭建Nginx+Python+MySQL环境的教程
Dec 25 #Python
Windows系统下使用flup搭建Nginx和Python环境的方法
Dec 25 #Python
You might like
PHP中文汉字验证码
2007/04/08 PHP
使用phpstorm和xdebug实现远程调试的方法
2015/12/29 PHP
PHP环形链表实现方法示例
2017/09/15 PHP
PHP实现关键字搜索后描红功能示例
2019/07/03 PHP
Javascript 同时提交多个Web表单的方法
2009/02/19 Javascript
关于setInterval、setTimeout在jQuery中的使用注意事项
2011/09/28 Javascript
33个优秀的 jQuery 图片展示插件分享
2012/03/14 Javascript
从数据库读取数据后将其输出成html标签的三种方法
2014/10/13 Javascript
js阻止浏览器默认行为的简单实例
2016/05/15 Javascript
关于JS中setTimeout()无法调用带参函数问题的解决方法
2016/06/21 Javascript
Google 地图获取API Key详细教程
2016/08/06 Javascript
javascript深拷贝和浅拷贝详解
2017/02/14 Javascript
jquery在启动页面时,自动加载数据的实例
2018/01/22 jQuery
vue完成项目后,打包成静态文件的方法
2018/09/03 Javascript
jQuery实现可编辑的表格
2019/12/11 jQuery
[01:56]2014DOTA2西雅图邀请赛 MVP外卡赛老队长精辟点评
2014/07/09 DOTA
Python实现的二维码生成小软件
2014/07/11 Python
python3 实现的人人影视网站自动签到
2016/06/19 Python
详谈Python2.6和Python3.0中对除法操作的异同
2017/04/28 Python
Python subprocess模块功能与常见用法实例详解
2018/06/28 Python
在python中将list分段并保存为array类型的方法
2019/07/15 Python
Django模板Templates使用方法详解
2019/07/19 Python
python开头的coding设置方法
2019/08/08 Python
Jupyter notebook如何修改平台字体
2020/05/13 Python
墨西哥运动服饰和鞋网上商店:Netshoes墨西哥
2016/07/28 全球购物
英国、欧洲和全球租车服务:Avis英国
2016/08/29 全球购物
简短大学毕业感言
2014/01/18 职场文书
《晚上的太阳》教学反思
2014/04/23 职场文书
8和9的加减法教学反思
2014/05/01 职场文书
社区优秀志愿者先进事迹
2014/05/09 职场文书
创先争优活动心得体会
2014/09/04 职场文书
正风肃纪查摆剖析材料
2014/10/10 职场文书
2015年师德师风承诺书
2015/01/22 职场文书
2015年银行个人工作总结
2015/05/14 职场文书
2019求职信大礼包
2019/05/15 职场文书
多表查询、事务、DCL
2021/04/05 MySQL