python实现爬虫统计学校BBS男女比例之数据处理,python实现爬虫统计学校BBS男女比例之多线程爬虫【10bet手机官网】
分类:web前端

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

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

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

一、数据分析

10bet手机官网 1

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

10bet手机官网 2

二、回滚

我们需要对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>u6027u522b</em>(.*?)</li')
  timeRe = re.compile(u'em>u4e0au6b21u6d3bu52a8u65f6u95f4</em>(.*?)</li')
  notexistRe = re.compile(u'(p>)u62b1u6b49uff0cu60a8u6307u5b9au7684u7528u6237u7a7au95f4u4e0du5b58u5728<')
  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:pythonProjectruisi'):
    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 FilesPython27python.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:pythonProjectruisi'):
  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:pythonProjectruisi'):
  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'u4fddu5bc6':
        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'u4fddu5bc6':
          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:pythonProjectruisi'):
    #没获取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:pythonProjectruisi'):
  # 有性别、活动时间
  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'u4fddu5bc6':
        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'u4fddu5bc6':
        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'u4fddu5bc6':
          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'u4fddu5bc6':
            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'u4fddu5bc6':
            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:pythonProjectruisi'):
    #没获取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实现爬虫统计学校BBS男女比例之多线程爬虫(二),python男女比例

接着第一篇继续学习。

一、数据分类

正确数据: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 %sn' % (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&uid=%s'
url2 = 'http://rs.xidian.edu.cn/home.php?mod=space&uid=%s&do=profile'
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 %sn' % (info, time)
          wfile = open(file1, 'a')
          wfile.write(info)
          wfile.close()
        else:
          info = '%s %sn' % (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 %sn' % (id, 'notexist')
            notexistfile.write(info)
            notexistfile.close()
          else:
            unkownsexfile = open(file4, 'a')
            info = '%d %sn' % (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>

这段代码就是爬取[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 %sn' % (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 %sn' % (info, time)
          wfile = open(file1, 'a')
          wfile.write(info)
          wfile.close()
        else:
          info = '%s %sn' % (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 %sn' % (id, 'notexist')
            notexistfile.write(info)
            notexistfile.close()
          else:
            unkownsexfile = open(file4, 'a')
            info = '%d %sn' % (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 <startNum> <endNum>'
    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>u6027u522b</em>(.*?)</li')
  timeRe = re.compile(u'em>u4e0au6b21u6d3bu52a8u65f6u95f4</em>(.*?)</li')
  notexistRe = re.compile(u'(p>)u62b1u6b49uff0cu60a8u6307u5b9au7684u7528u6237u7a7au95f4u4e0du5b58u5728<')
  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 = '..\newRuisi\correct%s-%s.txt' % (startNum, endNum)
  file2 = '..\newRuisi\errTime%s-%s.txt' % (startNum, endNum)
  file3 = '..\newRuisi\notexist%s-%s.txt' % (startNum, endNum)
  file4 = '..\newRuisi\unkownsex%s-%s.txt' % (startNum, endNum)
  file5 = '..\newRuisi\httperror%s-%s.txt' % (startNum, endNum)
  searchWeb(xrange(startNum,endNum))
  # numThread = 10
  # searchWeb(xrange(endNum))
  # total = 0
  # for i in xrange(numThread):
  # data = xrange(1+i,endNum,numThread)
  #   total =+ len(data)
  #   t=threading.Thread(target=searchWeb,args=(data,))
  #   t.start()
  # print total

main()

多线程爬虫

代码

# coding=utf-8
from subprocess import Popen
import subprocess
import threading,time


startn = 1
endn = 300001
step =1000
total = (endn - startn + 1 ) /step
ISOTIMEFORMAT='%Y-%m-%d %X'

#hardcode 3 threads
#沒有深究3个线程好还是4或者更多个线程好
#输出格式化的年月日时分秒
#输出程序的耗时(以秒为单位)
for i in xrange(0,total,3):
  startNumber = startn + step * i
  startTime = time.clock()

  s0 = startNumber
  s1 = startNumber + step
  s2 = startNumber + step*2
  s3 = startNumber + step*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)

  startftime ='[ '+ time.strftime( ISOTIMEFORMAT, time.localtime() ) + ' ] '

  print startftime + '%s - %s download start... ' %(s0, s1)
  print startftime + '%s - %s download start... ' %(s1, s2)
  print startftime + '%s - %s download start... ' %(s2, s3)

  p1.communicate()
  p2.communicate()
  p3.communicate()

  endftime = '[ '+ time.strftime( ISOTIMEFORMAT, time.localtime() ) + ' ] '
  print endftime + '%s - %s download end !!! ' %(s0, s1)
  print endftime + '%s - %s download end !!! ' %(s1, s2)
  print endftime + '%s - %s download end !!! ' %(s2, s3)

  endTime = time.clock()
  print "cost time " + str(endTime - startTime) + " s"
  time.sleep(5)

这儿是记录时间戳的日志:

"D:Program FilesPython27python.exe" E:/pythonProject/webCrawler/sum.py
[ 2015-11-23 11:31:15 ] 1 - 1001 download start... 
[ 2015-11-23 11:31:15 ] 1001 - 2001 download start... 
[ 2015-11-23 11:31:15 ] 2001 - 3001 download start... 
[ 2015-11-23 11:53:44 ] 1 - 1001 download end !!! 
[ 2015-11-23 11:53:44 ] 1001 - 2001 download end !!! 
[ 2015-11-23 11:53:44 ] 2001 - 3001 download end !!! 
cost time 1348.99480677 s
[ 2015-11-23 11:53:50 ] 3001 - 4001 download start... 
[ 2015-11-23 11:53:50 ] 4001 - 5001 download start... 
[ 2015-11-23 11:53:50 ] 5001 - 6001 download start... 
[ 2015-11-23 12:16:56 ] 3001 - 4001 download end !!! 
[ 2015-11-23 12:16:56 ] 4001 - 5001 download end !!! 
[ 2015-11-23 12:16:56 ] 5001 - 6001 download end !!! 
cost time 1386.06407734 s
[ 2015-11-23 12:17:01 ] 6001 - 7001 download start... 
[ 2015-11-23 12:17:01 ] 7001 - 8001 download start... 
[ 2015-11-23 12:17:01 ] 8001 - 9001 download start... 

上面是多线程的Log记录,从下面可以看出,1000个用户平均需要500s,一个id需要0.5s。500*300/3600 = 41.666666666667小时,大概需要两天的时间。
我们再试验一次单线程爬虫的耗时,记录如下:

"D:Program FilesPython27python.exe" E:/pythonProject/webCrawler/sum.py
1 - 1001 download start... 
1 - 1001 download end !!! 
cost time 1583.65911889 s
1001 - 2001 download start... 
1001 - 2001 download end !!! 
cost time 1342.46874278 s
2001 - 3001 download start... 
2001 - 3001 download end !!! 
cost time 1327.10885725 s
3001 - 4001 download start... 

我们发现一次线程爬取1000个用户耗时的时间也需要1500s,而多线程程序是3*1000个用户耗时1500s。

故多线程确实能比单线程省很多时间。

Note: 在getInfo(myurl, seWord)里有time.sleep(0.3)这样一段代码,是为了防止批判访问BBS,而被BBS拒绝访问。这个0.3s对于上文多线程和单线程的统计时间有影响。
最后附上原始的,没有带时间戳的记录。(加上时间戳,可以知道程序什么时候开始爬虫的,以应对线程卡死情况。)

"D:Program FilesPython27python.exe" E:/pythonProject/webCrawler/sum.py
1 - 1001 download start... 
1001 - 2001 download start... 
2001 - 3001 download start... 
1 - 1001 download end !!! 
1001 - 2001 download end !!! 
2001 - 3001 download end !!! 
cost time 1532.74102812 s
3001 - 4001 download start... 
4001 - 5001 download start... 
5001 - 6001 download start... 
3001 - 4001 download end !!! 
4001 - 5001 download end !!! 
5001 - 6001 download end !!! 
cost time 2652.01624951 s
6001 - 7001 download start... 
7001 - 8001 download start... 
8001 - 9001 download start... 
6001 - 7001 download end !!! 
7001 - 8001 download end !!! 
8001 - 9001 download end !!! 
cost time 1880.61513696 s
9001 - 10001 download start... 
10001 - 11001 download start... 
11001 - 12001 download start... 
9001 - 10001 download end !!! 
10001 - 11001 download end !!! 
11001 - 12001 download end !!! 
cost time 1634.40575553 s
12001 - 13001 download start... 
13001 - 14001 download start... 
14001 - 15001 download start... 
12001 - 13001 download end !!! 
13001 - 14001 download end !!! 
14001 - 15001 download end !!! 
cost time 1403.62795496 s
15001 - 16001 download start... 
16001 - 17001 download start... 
17001 - 18001 download start... 
15001 - 16001 download end !!! 
16001 - 17001 download end !!! 
17001 - 18001 download end !!! 
cost time 1271.42177906 s
18001 - 19001 download start... 
19001 - 20001 download start... 
20001 - 21001 download start... 
18001 - 19001 download end !!! 
19001 - 20001 download end !!! 
20001 - 21001 download end !!! 
cost time 1476.04122024 s
21001 - 22001 download start... 
22001 - 23001 download start... 
23001 - 24001 download start... 
21001 - 22001 download end !!! 
22001 - 23001 download end !!! 
23001 - 24001 download end !!! 
cost time 1431.37074164 s
24001 - 25001 download start... 
25001 - 26001 download start... 
26001 - 27001 download start... 
24001 - 25001 download end !!! 
25001 - 26001 download end !!! 
26001 - 27001 download end !!! 
cost time 1411.45186874 s
27001 - 28001 download start... 
28001 - 29001 download start... 
29001 - 30001 download start... 
27001 - 28001 download end !!! 
28001 - 29001 download end !!! 
29001 - 30001 download end !!! 
cost time 1396.88837788 s
30001 - 31001 download start... 
31001 - 32001 download start... 
32001 - 33001 download start... 
30001 - 31001 download end !!! 
31001 - 32001 download end !!! 
32001 - 33001 download end !!! 
cost time 1389.01316718 s
33001 - 34001 download start... 
34001 - 35001 download start... 
35001 - 36001 download start... 
33001 - 34001 download end !!! 
34001 - 35001 download end !!! 
35001 - 36001 download end !!! 
cost time 1318.16040825 s
36001 - 37001 download start... 
37001 - 38001 download start... 
38001 - 39001 download start... 
36001 - 37001 download end !!! 
37001 - 38001 download end !!! 
38001 - 39001 download end !!! 
cost time 1362.59222822 s
39001 - 40001 download start... 
40001 - 41001 download start... 
41001 - 42001 download start... 
39001 - 40001 download end !!! 
40001 - 41001 download end !!! 
41001 - 42001 download end !!! 
cost time 1253.62498539 s
42001 - 43001 download start... 
43001 - 44001 download start... 
44001 - 45001 download start... 
42001 - 43001 download end !!! 
43001 - 44001 download end !!! 
44001 - 45001 download end !!! 
cost time 1313.50461988 s
45001 - 46001 download start... 
46001 - 47001 download start... 
47001 - 48001 download start... 
45001 - 46001 download end !!! 
46001 - 47001 download end !!! 
47001 - 48001 download end !!! 
cost time 1322.32317331 s
48001 - 49001 download start... 
49001 - 50001 download start... 
50001 - 51001 download start... 
48001 - 49001 download end !!! 
49001 - 50001 download end !!! 
50001 - 51001 download end !!! 
cost time 1381.58027296 s
51001 - 52001 download start... 
52001 - 53001 download start... 
53001 - 54001 download start... 
51001 - 52001 download end !!! 
52001 - 53001 download end !!! 
53001 - 54001 download end !!! 
cost time 1357.78699459 s
54001 - 55001 download start... 
55001 - 56001 download start... 
56001 - 57001 download start... 
54001 - 55001 download end !!! 
55001 - 56001 download end !!! 
56001 - 57001 download end !!! 
cost time 1359.76377246 s
57001 - 58001 download start... 
58001 - 59001 download start... 
59001 - 60001 download start... 
57001 - 58001 download end !!! 
58001 - 59001 download end !!! 
59001 - 60001 download end !!! 
cost time 1335.47829775 s
60001 - 61001 download start... 
61001 - 62001 download start... 
62001 - 63001 download start... 
60001 - 61001 download end !!! 
61001 - 62001 download end !!! 
62001 - 63001 download end !!! 
cost time 1354.82727645 s
63001 - 64001 download start... 
64001 - 65001 download start... 
65001 - 66001 download start... 
63001 - 64001 download end !!! 
64001 - 65001 download end !!! 
65001 - 66001 download end !!! 
cost time 1260.54731607 s
66001 - 67001 download start... 
67001 - 68001 download start... 
68001 - 69001 download start... 
66001 - 67001 download end !!! 
67001 - 68001 download end !!! 
68001 - 69001 download end !!! 
cost time 1363.58255686 s
69001 - 70001 download start... 
70001 - 71001 download start... 
71001 - 72001 download start... 
69001 - 70001 download end !!! 
70001 - 71001 download end !!! 
71001 - 72001 download end !!! 
cost time 1354.17163074 s
72001 - 73001 download start... 
73001 - 74001 download start... 
74001 - 75001 download start... 
72001 - 73001 download end !!! 
73001 - 74001 download end !!! 
74001 - 75001 download end !!! 
cost time 1335.00425259 s
75001 - 76001 download start... 
76001 - 77001 download start... 
77001 - 78001 download start... 
75001 - 76001 download end !!! 
76001 - 77001 download end !!! 
77001 - 78001 download end !!! 
cost time 1360.44054978 s
78001 - 79001 download start... 
79001 - 80001 download start... 
80001 - 81001 download start... 
78001 - 79001 download end !!! 
79001 - 80001 download end !!! 
80001 - 81001 download end !!! 
cost time 1369.72662457 s
81001 - 82001 download start... 
82001 - 83001 download start... 
83001 - 84001 download start... 
81001 - 82001 download end !!! 
82001 - 83001 download end !!! 
83001 - 84001 download end !!! 
cost time 1369.95550676 s
84001 - 85001 download start... 
85001 - 86001 download start... 
86001 - 87001 download start... 
84001 - 85001 download end !!! 
85001 - 86001 download end !!! 
86001 - 87001 download end !!! 
cost time 1482.53886433 s
87001 - 88001 download start... 
88001 - 89001 download start... 
89001 - 90001 download start... 

以上就是关于python实现爬虫统计学校BBS男女比例的第二篇,重点介绍了多线程爬虫,希望对大家的学习有所帮助。

接着第一篇继续学习。

一、数据分析

您可能感兴趣的文章:

  • python实现统计汉字/英文单词数的正则表达式
  • 使用python统计文件行数示例分享
  • python用字典统计单词或汉字词个数示例
  • Python统计列表中的重复项出现的次数的方法
  • python统计一个文本中重复行数的方法
  • python统计字符串中指定字符出现次数的方法
  • python实现爬虫统计学校BBS男女比例(一)
  • python实现爬虫统计学校BBS男女比例之多线程爬虫(二)

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

您可能感兴趣的文章:

  • python实现统计汉字/英文单词数的正则表达式
  • 使用python统计文件行数示例分享
  • python用字典统计单词或汉字词个数示例
  • Python统计列表中的重复项出现的次数的方法
  • python统计一个文本中重复行数的方法
  • python统计字符串中指定字符出现次数的方法
  • python实现爬虫统计学校BBS男女比例(一)
  • python实现爬虫统计学校BBS男女比例之数据处理(三)

接着第一篇继续学习。 一、数据分类 正确数据:id、性别、活动时...

一、数据分类

10bet手机官网 3

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

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

放在这个文件里file1 = 'ruisi\correct%s-%s.txt' % (startNum, endNum)

10bet手机官网 4

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

二、回滚

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

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

放这个文件里file2 = 'ruisi\errTime%s-%s.txt' % (startNum, endNum)

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

数据格式为2566 女 notime

//httperror265001_266001.txt
265002 httperror
265002 httperror
265002 httperror
265002 httperror
265003 httperror
265003 httperror
265003 httperror
265003 httperror
  • 用户不存在:该id没有对应的用户

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

放这个文件里file3 = 'ruisi\notexist%s-%s.txt' % (startNum, endNum)

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

数据格式为29005 notexist

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>u6027u522b(.*?)u4e0au6b21u6d3bu52a8u65f6u95f4(.*?))u62b1u6b49uff0cu60a8u6307u5b9au7684u7528u6237u7a7au95f4u4e0du5b58u5728

本代码为了简便,没有再把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'
  • 未知性别:有id,但是性别从网页上无法得知(经检查,这种情况也没有活动时间)  

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

放这个文件里 file4 = 'ruisi\unkownsex%s-%s.txt' % (startNum, endNum)

"D:Program FilesPython27python.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

数据格式 221794 unkownsex

三、单线程统计unkownsex 数据

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

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

放这个文件里 file5 = 'ruisi\httperror%s-%s.txt' % (startNum, endNum)

数据格式如下:

数据格式 271004 httperror

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:pythonProjectruisi'):
  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"

如何不间断得爬虫信息

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

  • 本项目有一个考虑:是不间断爬取信息,如果因为断网、BBS服务器故障啥的,我的爬虫程序就退出的话。那我们还得从间断的地方继续爬,或者更麻烦的是从头开始爬。

  • 所以,我采取的方法是,如果遇到故障,就把这些异常的id记录下来。等一次遍历之后,才对这些异常的id进行重新爬取性别。

  • 本文系列(一)给出了一个 getInfo(myurl, seWord),通过给定链接和给定正则表达式爬取信息。

  • 这个函数可以用来查看性别的最后活动时间信息。

  • 我们再定义一个安全的爬取函数,不会间断程序运行的,这儿用到try except异常处理。

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

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

四、单线程统计 correct 数据

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 %sn' % (myid, 'httperror')
      httperrorfile.write(info)
      httperrorfile.close()
      return 'httperror'

数据格式如下:

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

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

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

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

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

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:pythonProjectruisi'):
  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'u4fddu5bc6':
        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"
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'
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 %sn' % (info, time)
          wfile = open(file1, 'a')
          wfile.write(info)
          wfile.close()
        else:
          info = '%s %sn' % (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 %sn' % (id, 'notexist')
            notexistfile.write(info)
            notexistfile.close()
          else:
            unkownsexfile = open(file4, 'a')
            info = '%d %sn' % (id, 'unkownsex')
            unkownsexfile.write(info)
            unkownsexfile.close()

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

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

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
 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
# 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'u4fddu5bc6':
          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:pythonProjectruisi'):
    #没获取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"

多线程爬取信息?

输出

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

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

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

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

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

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

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

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

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()
# 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:pythonProjectruisi'):
  # 有性别、活动时间
  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'u4fddu5bc6':
        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'u4fddu5bc6':
        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"

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

输出为

用法:python ruisi.py <startNum> <endNum>

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

这段代码就是爬取[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 %sn' % (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 %sn' % (info, time)
          wfile = open(file1, 'a')
          wfile.write(info)
          wfile.close()
        else:
          info = '%s %sn' % (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 %sn' % (id, 'notexist')
            notexistfile.write(info)
            notexistfile.close()
          else:
            unkownsexfile = open(file4, 'a')
            info = '%d %sn' % (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 <startNum> <endNum>'
    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>u6027u522b</em>(.*?)</li')
  timeRe = re.compile(u'em>u4e0au6b21u6d3bu52a8u65f6u95f4</em>(.*?)</li')
  notexistRe = re.compile(u'(p>)u62b1u6b49uff0cu60a8u6307u5b9au7684u7528u6237u7a7au95f4u4e0du5b58u5728<')
  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 = '..\newRuisi\correct%s-%s.txt' % (startNum, endNum)
  file2 = '..\newRuisi\errTime%s-%s.txt' % (startNum, endNum)
  file3 = '..\newRuisi\notexist%s-%s.txt' % (startNum, endNum)
  file4 = '..\newRuisi\unkownsex%s-%s.txt' % (startNum, endNum)
  file5 = '..\newRuisi\httperror%s-%s.txt' % (startNum, endNum)
  searchWeb(xrange(startNum,endNum))
  # numThread = 10
  # searchWeb(xrange(endNum))
  # total = 0
  # for i in xrange(numThread):
  # data = xrange(1+i,endNum,numThread)
  #   total =+ len(data)
  #   t=threading.Thread(target=searchWeb,args=(data,))
  #   t.start()
  # print total

main()
__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'u4fddu5bc6':
          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'u4fddu5bc6':
            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'u4fddu5bc6':
            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:pythonProjectruisi'):
    #没获取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
可以看出多线程还是优于单线程的,由于使用的同步,数据统计是一直的。

# coding=utf-8
from subprocess import Popen
import subprocess
import threading,time


startn = 1
endn = 300001
step =1000
total = (endn - startn + 1 ) /step
ISOTIMEFORMAT='%Y-%m-%d %X'

#hardcode 3 threads
#沒有深究3个线程好还是4或者更多个线程好
#输出格式化的年月日时分秒
#输出程序的耗时(以秒为单位)
for i in xrange(0,total,3):
  startNumber = startn + step * i
  startTime = time.clock()

  s0 = startNumber
  s1 = startNumber + step
  s2 = startNumber + step*2
  s3 = startNumber + step*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)

  startftime ='[ '+ time.strftime( ISOTIMEFORMAT, time.localtime() ) + ' ] '

  print startftime + '%s - %s download start... ' %(s0, s1)
  print startftime + '%s - %s download start... ' %(s1, s2)
  print startftime + '%s - %s download start... ' %(s2, s3)

  p1.communicate()
  p2.communicate()
  p3.communicate()

  endftime = '[ '+ time.strftime( ISOTIMEFORMAT, time.localtime() ) + ' ] '
  print endftime + '%s - %s download end !!! ' %(s0, s1)
  print endftime + '%s - %s download end !!! ' %(s1, s2)
  print endftime + '%s - %s download end !!! ' %(s2, s3)

  endTime = time.clock()
  print "cost time " + str(endTime - startTime) + " s"
  time.sleep(5)

注意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()
"D:Program FilesPython27python.exe" E:/pythonProject/webCrawler/sum.py
[ 2015-11-23 11:31:15 ] 1 - 1001 download start... 
[ 2015-11-23 11:31:15 ] 1001 - 2001 download start... 
[ 2015-11-23 11:31:15 ] 2001 - 3001 download start... 
[ 2015-11-23 11:53:44 ] 1 - 1001 download end !!! 
[ 2015-11-23 11:53:44 ] 1001 - 2001 download end !!! 
[ 2015-11-23 11:53:44 ] 2001 - 3001 download end !!! 
cost time 1348.99480677 s
[ 2015-11-23 11:53:50 ] 3001 - 4001 download start... 
[ 2015-11-23 11:53:50 ] 4001 - 5001 download start... 
[ 2015-11-23 11:53:50 ] 5001 - 6001 download start... 
[ 2015-11-23 12:16:56 ] 3001 - 4001 download end !!! 
[ 2015-11-23 12:16:56 ] 4001 - 5001 download end !!! 
[ 2015-11-23 12:16:56 ] 5001 - 6001 download end !!! 
cost time 1386.06407734 s
[ 2015-11-23 12:17:01 ] 6001 - 7001 download start... 
[ 2015-11-23 12:17:01 ] 7001 - 8001 download start... 
[ 2015-11-23 12:17:01 ] 8001 - 9001 download start...

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

上面是多线程的Log记录,从下面可以看出,1000个用户平均需要500s,一个id需要0.5s。500*300/3600 = 41.666666666667小时,大概需要两天的时间。
我们再试验一次单线程爬虫的耗时,记录如下:

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

"D:Program FilesPython27python.exe" E:/pythonProject/webCrawler/sum.py
1 - 1001 download start... 
1 - 1001 download end !!! 
cost time 1583.65911889 s
1001 - 2001 download start... 
1001 - 2001 download end !!! 
cost time 1342.46874278 s
2001 - 3001 download start... 
2001 - 3001 download end !!! 
cost time 1327.10885725 s
3001 - 4001 download start...

我们发现一次线程爬取1000个用户耗时的时间也需要1500s,而多线程程序是3*1000个用户耗时1500s。

故多线程确实能比单线程省很多时间。

Note:
在getInfo(myurl, seWord)里有time.sleep(0.3)这样一段代码,是为了防止批判访问BBS,而被BBS拒绝访问。这个0.3s对于上文多线程和单线程的统计时间有影响。
最后附上原始的,没有带时间戳的记录。(加上时间戳,可以知道程序什么时候开始爬虫的,以应对线程卡死情况。)

"D:Program FilesPython27python.exe" E:/pythonProject/webCrawler/sum.py
1 - 1001 download start... 
1001 - 2001 download start... 
2001 - 3001 download start... 
1 - 1001 download end !!! 
1001 - 2001 download end !!! 
2001 - 3001 download end !!! 
cost time 1532.74102812 s
3001 - 4001 download start... 
4001 - 5001 download start... 
5001 - 6001 download start... 
3001 - 4001 download end !!! 
4001 - 5001 download end !!! 
5001 - 6001 download end !!! 
cost time 2652.01624951 s
6001 - 7001 download start... 
7001 - 8001 download start... 
8001 - 9001 download start... 
6001 - 7001 download end !!! 
7001 - 8001 download end !!! 
8001 - 9001 download end !!! 
cost time 1880.61513696 s
9001 - 10001 download start... 
10001 - 11001 download start... 
11001 - 12001 download start... 
9001 - 10001 download end !!! 
10001 - 11001 download end !!! 
11001 - 12001 download end !!! 
cost time 1634.40575553 s
12001 - 13001 download start... 
13001 - 14001 download start... 
14001 - 15001 download start... 
12001 - 13001 download end !!! 
13001 - 14001 download end !!! 
14001 - 15001 download end !!! 
cost time 1403.62795496 s
15001 - 16001 download start... 
16001 - 17001 download start... 
17001 - 18001 download start... 
15001 - 16001 download end !!! 
16001 - 17001 download end !!! 
17001 - 18001 download end !!! 
cost time 1271.42177906 s
18001 - 19001 download start... 
19001 - 20001 download start... 
20001 - 21001 download start... 
18001 - 19001 download end !!! 
19001 - 20001 download end !!! 
20001 - 21001 download end !!! 
cost time 1476.04122024 s
21001 - 22001 download start... 
22001 - 23001 download start... 
23001 - 24001 download start... 
21001 - 22001 download end !!! 
22001 - 23001 download end !!! 
23001 - 24001 download end !!! 
cost time 1431.37074164 s
24001 - 25001 download start... 
25001 - 26001 download start... 
26001 - 27001 download start... 
24001 - 25001 download end !!! 
25001 - 26001 download end !!! 
26001 - 27001 download end !!! 
cost time 1411.45186874 s
27001 - 28001 download start... 
28001 - 29001 download start... 
29001 - 30001 download start... 
27001 - 28001 download end !!! 
28001 - 29001 download end !!! 
29001 - 30001 download end !!! 
cost time 1396.88837788 s
30001 - 31001 download start... 
31001 - 32001 download start... 
32001 - 33001 download start... 
30001 - 31001 download end !!! 
31001 - 32001 download end !!! 
32001 - 33001 download end !!! 
cost time 1389.01316718 s
33001 - 34001 download start... 
34001 - 35001 download start... 
35001 - 36001 download start... 
33001 - 34001 download end !!! 
34001 - 35001 download end !!! 
35001 - 36001 download end !!! 
cost time 1318.16040825 s
36001 - 37001 download start... 
37001 - 38001 download start... 
38001 - 39001 download start... 
36001 - 37001 download end !!! 
37001 - 38001 download end !!! 
38001 - 39001 download end !!! 
cost time 1362.59222822 s
39001 - 40001 download start... 
40001 - 41001 download start... 
41001 - 42001 download start... 
39001 - 40001 download end !!! 
40001 - 41001 download end !!! 
41001 - 42001 download end !!! 
cost time 1253.62498539 s
42001 - 43001 download start... 
43001 - 44001 download start... 
44001 - 45001 download start... 
42001 - 43001 download end !!! 
43001 - 44001 download end !!! 
44001 - 45001 download end !!! 
cost time 1313.50461988 s
45001 - 46001 download start... 
46001 - 47001 download start... 
47001 - 48001 download start... 
45001 - 46001 download end !!! 
46001 - 47001 download end !!! 
47001 - 48001 download end !!! 
cost time 1322.32317331 s
48001 - 49001 download start... 
49001 - 50001 download start... 
50001 - 51001 download start... 
48001 - 49001 download end !!! 
49001 - 50001 download end !!! 
50001 - 51001 download end !!! 
cost time 1381.58027296 s
51001 - 52001 download start... 
52001 - 53001 download start... 
53001 - 54001 download start... 
51001 - 52001 download end !!! 
52001 - 53001 download end !!! 
53001 - 54001 download end !!! 
cost time 1357.78699459 s
54001 - 55001 download start... 
55001 - 56001 download start... 
56001 - 57001 download start... 
54001 - 55001 download end !!! 
55001 - 56001 download end !!! 
56001 - 57001 download end !!! 
cost time 1359.76377246 s
57001 - 58001 download start... 
58001 - 59001 download start... 
59001 - 60001 download start... 
57001 - 58001 download end !!! 
58001 - 59001 download end !!! 
59001 - 60001 download end !!! 
cost time 1335.47829775 s
60001 - 61001 download start... 
61001 - 62001 download start... 
62001 - 63001 download start... 
60001 - 61001 download end !!! 
61001 - 62001 download end !!! 
62001 - 63001 download end !!! 
cost time 1354.82727645 s
63001 - 64001 download start... 
64001 - 65001 download start... 
65001 - 66001 download start... 
63001 - 64001 download end !!! 
64001 - 65001 download end !!! 
65001 - 66001 download end !!! 
cost time 1260.54731607 s
66001 - 67001 download start... 
67001 - 68001 download start... 
68001 - 69001 download start... 
66001 - 67001 download end !!! 
67001 - 68001 download end !!! 
68001 - 69001 download end !!! 
cost time 1363.58255686 s
69001 - 70001 download start... 
70001 - 71001 download start... 
71001 - 72001 download start... 
69001 - 70001 download end !!! 
70001 - 71001 download end !!! 
71001 - 72001 download end !!! 
cost time 1354.17163074 s
72001 - 73001 download start... 
73001 - 74001 download start... 
74001 - 75001 download start... 
72001 - 73001 download end !!! 
73001 - 74001 download end !!! 
74001 - 75001 download end !!! 
cost time 1335.00425259 s
75001 - 76001 download start... 
76001 - 77001 download start... 
77001 - 78001 download start... 
75001 - 76001 download end !!! 
76001 - 77001 download end !!! 
77001 - 78001 download end !!! 
cost time 1360.44054978 s
78001 - 79001 download start... 
79001 - 80001 download start... 
80001 - 81001 download start... 
78001 - 79001 download end !!! 
79001 - 80001 download end !!! 
80001 - 81001 download end !!! 
cost time 1369.72662457 s
81001 - 82001 download start... 
82001 - 83001 download start... 
83001 - 84001 download start... 
81001 - 82001 download end !!! 
82001 - 83001 download end !!! 
83001 - 84001 download end !!! 
cost time 1369.95550676 s
84001 - 85001 download start... 
85001 - 86001 download start... 
86001 - 87001 download start... 
84001 - 85001 download end !!! 
85001 - 86001 download end !!! 
86001 - 87001 download end !!! 
cost time 1482.53886433 s
87001 - 88001 download start... 
88001 - 89001 download start... 
89001 - 90001 download start...

本文由10bet手机官网发布于web前端,转载请注明出处:python实现爬虫统计学校BBS男女比例之数据处理,python实现爬虫统计学校BBS男女比例之多线程爬虫【10bet手机官网】

上一篇:python使用turtle库绘制时钟,Tkinter实现简易计算器功能【10bet手机官网】 下一篇:python实现颜色空间转换程序
猜你喜欢
热门排行
精彩图文