zoukankan      html  css  js  c++  java
  • 从Python爬虫到SAE云和微信公众号:一、糗事百科爬虫

    这是写给自己玩的练习项目,从糗事百科中爬取段子放到微信公众号上去,这样我就能随时随地的看段子了,啊哈哈哈

    项目结构

    1.糗事百科爬虫:Pthon实现,MySQL做持久化存储

    2.用免费的新浪SAE云搭建微信公众号的服务器

    3.微信公众号部分

                                                 主要结构内容划分

    糗事百科爬虫

    技术实现:Python2.7

    插件使用:re,urllib2,pymysql。没有使用beatifulsoap

    实现思路:

    1)起始:从糗事百科的“穿越”(http://www.qiushibaike.com/history/)栏,可以随机打开之前的某一天的糗事页面

    2)查重:根据日期判断数据库中是否已经抓取过此页面

    3)页面下载:如果没有抓去过,则下载当天前两个页面到页面队列中,等待解析

    4)解析页面:糗事、页面url、日期、下一天的url(页面中随机展示)

    5)持久化存储:将分离出来的逐个段子和其他信息,存储到mysql中

    6)下一轮抓取:根据4中得到的下一页url,进入2流程(此步骤也可以是不断刷新“穿越”页面得到新的页面,即进入1流程)

    7)数据输出:为了能在新浪云SAE中使用段子数据(免费云空间不能使用mysql),从mysql中导出糗事段子为文本文件

    下面是爬虫中最主要的部分,流程控制的代码和页面解析的代码:

     qiushi_history_main.py代码:控制整个流程

    # -*- coding: utf-8 -*-
    import thread
    import time
    from qiushi_history_spider import html_parser
    from qiushi_history_spider import html_outputer
    from qiushi_history_spider import txt_outputer
    from qiushi_history_spider import page_manger
    from qiushi_history_spider import mysql_outputer
    from qiushi_history_spider import date_manager
    import urllib2
    
    
    # ----------- 加载处理糗事百科 -----------
    class Spider_Model:
        # 声明self:含有page pages enabled
        def __init__(self):
            self.pagemanger = page_manger.PageManager()
            self.htmlparser = html_parser.HtmlParser()
            # self.outputer=html_outputer.HtmlOutputer()
            self.txtoutputer = txt_outputer.TxtOutputer()
            self.mysqlOutputer = mysql_outputer.MysqlOutputer()
            self.datemanager = date_manager.DateManager()
            self.page = 1
            self.pages = []
            self.storys = []
            self.enable = True
            self.maxPageNum = 400;
    
        def Start(self):
            self.enable = True
            page = self.page
            print u'正在加载中请稍候......'
            # 新建一个线程在后台加载段子并存储
            startUrl = 'http://www.qiushibaike.com/history/'
            self.pagemanger.AddUrl(startUrl)
            connection = self.mysqlOutputer.open_conneciton()  # 打开数据库连接
            self.datemanager.set_conn(connection)
            thread.start_new_thread(self.pagemanger.LoadPage, ())
    
            time.sleep(3)
            self.pages = self.pagemanger.pages
            # ----------- 加载处理糗事百科 -----------
            while self.enable:
                # 存储并检验是否到达预订页数
                if (page > self.maxPageNum):
                    self.pagemanger.enable = False
                    self.enable = False
                    break
    
                # 如果self的page数组中存有元素
                # 等待,防止pagemanager尚未读取完毕
                time.sleep(2)
                if self.pages:
                    if(len(self.pages)<=0):
                        continue
                    nowPage = self.pages[0]
    
                    if(nowPage==None):
                        del self.pages[0]
                        continue
                    del self.pages[0]
                    #读取内容
                    self.storys, thisUrlCode, nextUrlCode, dateStr = self.htmlparser.GetStorys2(nowPage)
    
                    # 判断是否重复
                    nodump = self.datemanager.no_duplicate(thisUrlCode)
                    if (nodump):
                        # region-----------保存当前日期的第一页---------------
                        self.datemanager.save_code(dateStr, thisUrlCode)
    
                        # 当前这一步没有用,现在的页面是不停的刷新‘穿越’页得到的
                        # print '存入待读列表:',startUrl + nextUrlCode
                        # self.pagemanger.AddUrl(startUrl + nextUrlCode)
    
                        dateStoryDic = {'story': self.storys, 'urlcode': thisUrlCode, 'date': dateStr, 'page': 1}
                        # print dateStoryDic
                        self.mysqlOutputer.collect_data(dateStoryDic)
                        self.PrintInfo(page, dateStr, thisUrlCode, nextUrlCode, 1)
                        page += 1
                        # endregion
    
                        # region-----------保存当前日期的第二页----------------
                        print "总页数:" + bytes(page), "日期:" + dateStr, "页码:" + bytes(2)
                        print "当前页Code:",thisUrlCode+'/page/2'
                        secondPageUrl = startUrl+thisUrlCode+'/page/2'
                        secondPage=self.pagemanger.ReadPageFromUrl(secondPageUrl)
    
                        if(secondPage==None):
                            print "加载此页失败!"
                            continue
                        self.storys, thisUrlCode, nextUrlCode, dateStr = self.htmlparser.GetStorys2(secondPage)
                        dateStoryDic = {'story': self.storys, 'urlcode': thisUrlCode, 'date': dateStr, 'page': 2}
                        self.mysqlOutputer.collect_data(dateStoryDic)
    
                        #page += 1
                        # endregion
    
                        self.mysqlOutputer.output_database()
                else:
                    self.enable = False
                    break
    
            self.mysqlOutputer.close_conneciton()
    
        # 打印输出 抓取的总页数,日期字符串,当前code,下一错的,当前日期第几页
        def PrintInfo(self, pagecount, datestr, thiscode, nextcode, pageIndex):
            print "总页数:" + bytes(pagecount), "日期:" + datestr, "页码:" + bytes(pageIndex)
            print "当前页Code:", thiscode
            #print "下一页Code:", nextcode
    
    
    # ----------- 程序的入口处 -----------
    # 1从数据库中读取所有id?
    # 2每次从首页(history)读取
    # 3首先获取当前页id,查重
    # 4如无重复则解析 存储到数据库
    # 5如果重复,直接读取下一页
    # 6读取下一页,重复2-6
    
    # Todolist:
    # 1.读取当天的第二页第三页
    # 2.输出mysql数据库中的数据到文件
    # 3.把datecode从数据库中读出到数组,以后查重更快
    
    myModel = Spider_Model()
    myModel.Start()
    
    # 否则 python错误Unhandled exception in thread started by Error in sys.excepthook
    time.sleep(3)
    主控制程序

    html_parser.py 页面解析代码

    # coding:utf8
    import re
    
    class HtmlParser(object):
        #auther AllenRobin  cnblogs.com/GISRSMAN/
        # 将所有的段子都扣出来,添加到列表中并且返回列表
        def __init__(self):
            self.storys=[]
            self.keywords=[]
            self.nextUrlCode=''
    
        #获得笑话正文、当前页Code、下一页Code
        def GetStorys(self,page):
            # print myPage
            unicodePage = page.decode("utf-8")
            # 找出所有class="content"的div标记
            #re.S是任意匹配模式,也就是.可以匹配换行符
            #myItems = re.findall('<div.*?class="content">(.*?)</div>',unicodePage,re.S)
            myItems = re.findall('<div.*?class="content">
    
    +<span>(.*?)</span>
    
    +</div>',unicodePage,re.S)
            thisUrlCode=re.findall('<link rel="canonical" href="http://www.qiushibaike.com/history/(.*?)/">',unicodePage,re.S)[0]
            nextUrlCode=re.findall('<a class="random" href="/history/(.*?)/".*?',unicodePage,re.S)[0]
    
            return myItems,thisUrlCode,nextUrlCode
    
        #获得笑话正文(作者赞数)、当前页Code、下一页Code
        def GetStorys2(self,pageContent):
            try:
                unicodePage= pageContent.decode("utf-8")
                pattern = re.compile('<div class="author clearfix">.*?<h2>(.*?)</h2>.*?<div.*?' +'content">
    
    +<span>(.*?)</span>
    
    +</div>(.*?)<span class="stats-vote"><i class="number">(.*?)</i>',re.S)
                
                #items三个要素依次为用户名、段子内容、赞数
                items = re.findall(pattern, pageContent)
    
                for item in items:
                    #去除段子内容中的查看全文
                    item[1].replace("<span class="contentForAll">查看全文","").replace("</span>","").replace("'",""")
                    #除去含有图片的
                    haveImg = re.search("img", item[3])
                    if  haveImg:
                        print item
                        del item
                        
                #可以将这三个合并到上一个提高效率
                thisUrlCode = re.findall('<link rel="canonical" href="http://www.qiushibaike.com/history/(.*?)/">', unicodePage, re.S)[0]
                nextUrlCode = re.findall('<a class="random" href="/history/(.*?)/".*?', unicodePage, re.S)[0]
                dateStrs = re.findall('<meta name="keywords" content="(.*?)" />', unicodePage, re.S)[0]
    
                return items,thisUrlCode,nextUrlCode,dateStrs
            except Exception, e:
                print Exception, ":", e
    页面解析代码

    整个爬虫项目放到Github上吧,欢迎fork

    GitHub地址:https://github.com/csdallen/qiushi_history_spider

    参考资源:

    Python开发简单爬虫

    Python爬虫实战一之爬取糗事百科段子

     

  • 相关阅读:
    spring mvc实现登录验证码
    sqlite可视化工具推荐
    【转载】oracle更新语法
    解决首次访问jenkins,输入默认密码之后,一直卡住问题
    Selenium+java
    ubuntu16.04安装Ros(kinetic版本)【亲测好用】
    Selenium+java
    Selenium+java
    Selenium+Java
    Selenium+java
  • 原文地址:https://www.cnblogs.com/GISRSMAN/p/6245401.html
Copyright © 2011-2022 走看看