#------------------------------------------------------------------------------------
# 理想论坛爬虫1.08,用于爬取主贴再爬子贴,数据存到文件里,再由insertDB.py读取插DB
# 增加同网址访问五次异常后退出机制
# 2018年4月27日
#------------------------------------------------------------------------------------
from bs4 import BeautifulSoup
import requests
import threading
import re
import time
import datetime
import os
import json
import colorama
from colorama import Fore, Back, Style
colorama.init()

user_agent='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
headers={'User-Agent':user_agent}

# 存储数据文件的目录
folder=""

# 主帖数组
topics=[]

#------------------------------------
# 在论坛页中寻找主贴
# pageUrl:论坛页url
#------------------------------------
def findTopics(pageUrl):
    print("\n开始读取页面"+pageUrl+"的帖子");

    try:
        rsp=requests.get(pageUrl,headers=headers)
        rsp.encoding = 'gb18030' #解决中文乱码问题的关键
        soup= BeautifulSoup(rsp.text,'html.parser',from_encoding='gb2312')

        for tbodys in soup.find_all('tbody'):
            pageCount=1
            url='none'
            title='none'

            for spans in tbodys.find_all('span',class_="forumdisplay"):
                for link in spans.find_all('a'):
                    if link and link.get("href"):
                       url="http://www.55188.com/"+link.get("href")
                       title=link.text

            for spans in tbodys.find_all('span',class_="threadpages"):
                for link in spans.find_all('a'):
                    pageCount=link.text

            if url!='none' and title!='none':
               topic={'pageCount':pageCount,'url':url,'title':title}
               #print("topic="+str(topic))
               topics.append(topic)

        #print("读取页面"+pageUrl+"的帖子完毕");
    except Exception as e:
        log("findTopics出现异常:"+str(e),'red')

#------------------------------------
# 以不同颜色在控制台输出文字
# pageUrl:论坛页url
#------------------------------------
def log(text,color):
    if color=='red':
        print(Fore.RED + text+ Style.RESET_ALL)
    elif color=='green':
        print(Fore.GREEN + text+ Style.RESET_ALL)
    elif color=='yellow':
        print(Fore.YELLOW + text+ Style.RESET_ALL)
    else:
        print(text)

#------------------------------------
# 找到并保存帖子的细节
# index:序号,url:地址,title:标题
#------------------------------------
def saveTopicDetail(index,url,title):
    infos=[]    # 找到的子贴信息
    tried=0;    # 尝试次数

    while(len(infos)==0):
        try:
            rsp=requests.get(url,headers=headers)
            rsp.encoding = 'gb18030' #解决中文乱码问题的关键
            soup= BeautifulSoup(rsp.text,'html.parser',from_encoding='gb2312')
            session = requests.session()
            session.keep_alive = False

            for divs in soup.find_all('div',class_="postinfo"):
                # 用正则表达式将多个空白字符替换成一个空格
                RE = re.compile(r'(\s+)')
                line=RE.sub(" ",divs.text)
                arr=line.split(' ')
                arrLength=len(arr)

                if arrLength==7:
                    info={'楼层':arr[1],
                          '作者':arr[2].replace('只看:',''),
                          '日期':arr[4],
                          '时间':arr[5],'title':title,'url':url}
                    infos.append(info)
                elif arrLength==8:
                    info={'楼层':arr[1],
                          '作者':arr[2].replace('只看:',''),
                          '日期':arr[5],
                          '时间':arr[6],'title':title,'url':url}
                    infos.append(info)

            #存文件
            filename=folder+"/"+str(index)+'.json'
            with open(filename,'w',encoding='utf-8') as fObj:
                json.dump(infos,fObj)
        except Exception as e:
            log("saveTopicDetail访问"+url+"时出现异常:"+str(e),'red')
            time.sleep(5)  # 如果出现异常,休息五秒后再试
            tried=tried+1

            if(tried>4):
                log("尝试5次仍无法访问:"+url+",只得跳过此页",'yellow')
                break

            continue

#------------------------------------
# 入口函数
# start:起始页,end:终止页
#------------------------------------
def main(start,end):
    # 创建目录
    currTime=time.strftime('%H_%M_%S',time.localtime(time.time()))
    global folder
    folder="./"+currTime
    os.makedirs(folder)
    print("目录"+folder+"创建完成")

    # 获取主贴
    print('\n将从以下页面获取主贴:');
    for i in range(start,end+1):
        pageUrl='http://www.55188.com/forum-8-'+str(i)+'.html' # 这个页是论坛页,即第1页,第2页等
        findTopics(pageUrl);

    n=len(topics)
    log("共读取到:"+str(n)+"个主贴",'green')

    # 获取主贴及其子贴
    finalTopics=[]
    index=0
    for topic in topics:
        end=int(topic['pageCount'])+1
        title=topic['title']

        for i in range(1,end):
            pattern='-(\d+)-(\d+)-(\d+)'
            newUrl=re.sub(pattern,lambda m:'-'+m.group(1)+'-'+str(i)+'-'+m.group(3),topic['url'])
            #print(newUrl)

            newTopic={'index':index,'url':newUrl,'title':title}
            finalTopics.append(newTopic)

            index=index+1

    n=len(finalTopics)
    log("共读取到:"+str(n)+"个帖子",'green')

    # 遍历finalTopics
    for newTopic in finalTopics:
        saveTopicDetail(newTopic['index'],newTopic['url'],newTopic['title']);

# 开始
main(1,10)

用得到的数据再用以下数据进行一次统计:

# 对发帖时间进行统计
import re
import pymysql

# 入口函数
def main():
    dic={':0}

    conn=pymysql.connect(host=',db='test',charset='utf8')

    cs=conn.cursor()
    cs.execute("select * from topic0426")
    results = cs.fetchall()

    for row in results:
        ttime=row[4]
        hour=ttime.split(':')[0]
        dic[hour]=dic[hour]+1

    conn.close()

    print(dic)
# 开始
main()

输出为:

C:\Users\horn1\Desktop\python\28>python sum.py
{': 10736}

C:\Users\horn1\Desktop\python\28>

统计图生成代码为:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <title> New Document </title>
  <meta name="Generator" content="EditPlus">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
 </head>
    <script src="ichart.1.2.min.js"></script>
 <body>
  <div id='canvasDiv'></div>
 </body>
</html>
<script type="text/javascript">
<!--
var dic={'00': 4305, '01': 1432, '02': 637, '03': 381, '04': 375, '05': 1304, '06': 3461, '07': 8311, '08': 22321, '09': 38335, '10': 37241, '11': 26504, '12': 13337, '13': 24906, '14': 29231, '15': 24648, '16': 13926, '17': 11280, '18': 9332, '19': 13444, '20': 19144, '21': 24731, '22': 20297, '23': 10736};

    //定义数据
    var data = [
        {name : '0-1点',  value : dic['00'],color:'#a5c2d5'},
           {name : '1-2点',  value : dic['01'],color:'#cbab4f'},
           {name : '2-3点',  value : dic['02'],color:'#76a871'},
           {name : '3-4点',  value : dic['03'],color:'#76a871'},
           {name : '4-5点',  value : dic['04'],color:'#a56f8f'},
           {name : '5-6点',  value : dic['05'],color:'#c12c44'},
           {name : '6-7点',  value : dic['06'],color:'#a56f8f'},
           {name : '7-8点',  value : dic['07'],color:'#9f7961'},
           {name : '8-9点',  value : dic['08'],color:'#76a871'},
           {name : '9-10点', value : dic['09'],color:'#6f83a5'},
        {name : '10-11点',value : dic['10'],color:'#a5c2d5'},
           {name : '11-12点',value : dic['11'],color:'#cbab4f'},
           {name : '12-13点',value : dic['12'],color:'#76a871'},
           {name : '13-14点',value : dic['13'],color:'#76a871'},
           {name : '14-15点',value : dic['14'],color:'#a56f8f'},
           {name : '15-16点',value : dic['15'],color:'#c12c44'},
           {name : '16-17点',value : dic['16'],color:'#a56f8f'},
           {name : '17-18点',value : dic['17'],color:'#9f7961'},
           {name : '18-19点',value : dic['18'],color:'#76a871'},
           {name : '19-20点',value : dic['19'],color:'#6f83a5'},
        {name : '20-21点',value : dic['20'],color:'#c12c44'},
           {name : '21-22点',value : dic['21'],color:'#a56f8f'},
           {name : '22-23点',value : dic['22'],color:'#9f7961'},
           {name : '23-24点',value : dic['23'],color:'#76a871'}
     ];
     $(function(){
        var chart = new iChart.Column2D({
            render : 'canvasDiv',//渲染的Dom目标,canvasDiv为Dom的ID
            data: data,//绑定数据
            title : '理想论坛每小时发帖量统计图表',//设置标题
            width : 1400,//设置宽度,默认单位为px
            height : 400,//设置高度,默认单位为px
            shadow:true,//激活阴影
            shadow_color:'#c7c7c7',//设置阴影颜色
            coordinate:{//配置自定义坐标轴
                scale:[{//配置自定义值轴
                     position:'left',//配置左值轴
                     start_scale:0,//设置开始刻度为0
                     end_scale:10000,//设置结束刻度为26
                     scale_space:5000,//设置刻度间距
                     listeners:{//配置事件
                        parseText:function(t,x,y){//设置解析值轴文本
                            return {text:t+""}
                        }
                    }
                }]
            }
        });
        //调用绘图方法开始绘图
        chart.draw();
    });
//-->
</script>

以上全体代码可以在这里下载:

https://files.cnblogs.com/files/xiandedanteng/lixiang108_20180427.rar

【pyhon】理想论坛爬虫1.08的更多相关文章

  1. 【python】理想论坛爬虫1.08

    #------------------------------------------------------------------------------------ # 理想论坛爬虫1.08, ...

  2. 【pyhon】理想论坛爬虫1.05版,将读取和写DB分离成两个文件

    下午再接再厉仿照Nodejs版的理想帖子爬虫把Python版的也改造了下,但美中不足的是完成任务的线程数量似乎停滞在100个左右,让人郁闷.原因还待查. 先把代码贴出来吧,也算个阶段性成果. 爬虫代码 ...

  3. 【pyhon】理想论坛爬虫1.07 退出问题,乱码问题至此解决,只是目前速度上还是遗憾点

    在 https://www.cnblogs.com/mengyu/p/6759671.html 的启示下,解决了乱码问题,在此向作者表示感谢. 至此,困扰我几天的乱码问题和退出问题都解决了,只是处理速 ...

  4. 【python】理想论坛爬虫长贴版1.00

    理想论坛有些长贴,针对这些长贴做统计可以知道某ID什么时段更活跃. 爬虫代码为: #---------------------------------------------------------- ...

  5. 【nodejs】理想论坛帖子下载爬虫1.08

    //====================================================== // 理想论坛帖子下载爬虫1.09 // 使用断点续传模式,因为网络传输会因各种原因中 ...

  6. 【Nodejs】理想论坛帖子爬虫1.01

    用Nodejs把Python实现过的理想论坛爬虫又实现了一遍,但是怎么判断所有回调函数都结束没有好办法,目前的spiderCount==spiderFinished判断法在多页情况下还是会提前中止. ...

  7. 【Python】理想论坛帖子读取爬虫1.04版

    1.01-1.03版本都有多线程争抢DB的问题,线程数一多问题就严重了. 这个版本把各线程要添加数据的SQL放到数组里,等最后一次性完成,这样就好些了.但乱码问题和未全部完成即退出现象还在,而且速度上 ...

  8. 【nodejs】理想论坛帖子下载爬虫1.07 使用request模块后稳定多了

    在1.06版本时,访问网页采用的时http.request,但调用次数多以后就问题来了. 寻找别的方案时看到了https://cnodejs.org/topic/53142ef833dbcb076d0 ...

  9. 【python】理想论坛帖子爬虫1.06

    昨天认识到在本期同时起一百个回调/线程后程序会崩溃,造成结果不可信. 于是决定用Python单线程操作,因为它理论上就用主线程跑不会有问题,只是时间长点. 写好程序后,测试了一中午,210个主贴,11 ...

随机推荐

  1. python 中__name__ = '__main__' 的作用,到底干嘛的?

    python 中__name__ = 'main' 的作用,到底干嘛的? 有句话经典的概括了这段代码的意义: "Make a script both importable and execu ...

  2. CI Weekly #15 | 据说新版 flow.ci Dashboard 界面很酷

    好久不见 :) 最近工程师们卯足了劲,全新的 flow.ci dashboard 页面 已经与所有用户见面了.更快捷地创建项目,构建列表页面新增分支,Pull Request 界面:侧边栏新增构建任务 ...

  3. 解决请求参数的中文乱码问题(get、post)

    2018-11-28 在web请求与响应中,会遇到乱码问题,比如填写表单数据时,难免会输入中文,姓名.公司名称等.由于HTML设置了浏览器在传递请求参数时,采用的编码方式是UTF-8,但在解码时采用的 ...

  4. 更好的浏览器动画实现 requestAnimationFrame

    requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API: js一般是借助setTimeout或setInterval这两个函数实现动画,性能不佳. css3动画,性能 ...

  5. CDOJ 1401 谭爷的黑暗沙拉 数学

    谭爷的黑暗沙拉 题目连接: http://mozhu.today/#/problem/show/1401 Description 谭爷有\(n\)种不同种类的食材(水果&蔬菜),他想做出一份总 ...

  6. 几张图理解Roll, Pitch, Yaw的含义

    Roll:翻滚    Pitch:俯仰    Yaw:偏航 有时候不知道它到底绕着哪个轴旋转得到的角,一个比较容易的记法是根据字母的排列顺序PRY分别对应XYZ轴进行旋转得到的角,即: Pitch是绕 ...

  7. MySQL: 查看一次SQL的执行时间都花在哪些环节上

    select @@profiling -- 看看当前的session的profiling打开没有 set profiling = 1 -- 如果没打开,打开一下 -- 执行一些sql select c ...

  8. spring---aop(6)---Spring AOP中ProxyFactoryBean介绍

    写在前面 这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP. 简单例子 Spring自己的AOP实现在于Pr ...

  9. CentOS 7 下编译安装lnmp之MySQL篇详解

    一.安装环境 宿主机=> win7,虚拟机 centos => 系统版本:centos-release-7-5.1804.el7.centos.x86_64 二.MySQL下载 MySQL ...

  10. PostgreSQL远程连接配置管理/账号密码分配(解决:致命错误: 用户 "postgres" Ident 认证失败)

    问题:致命错误: 用户 "postgres" Ident 认证失败 说明:这个是由于没有配置远程访问且认证方式没改造成的,只需要更改使用账号密码认证即可. 解决:找到pg_hba. ...