美文网首页
二、数据清洗,对广告信息说不

二、数据清洗,对广告信息说不

作者: 北塔资讯 | 来源:发表于2017-10-27 16:53 被阅读69次

    在上一章,我们已经拿到了40G的数据,如何分析这些文档,是最主要的目标。由于网站在ppt文档中暴力插入了广告链接,删掉这些与内容无关的信息就是文档解析的第一步。

    本文主要是两部分信息:

    • 文档脏数据的定位与删除;
    • MSOffice接口简单介绍;

    1、“脏数据”都有什么?

    就目标站点来说,往文档中插的信息无外乎这三类:

    • 文档描述信息;
    • 文本框连接;
    • 广告页;
    文档描述信息 文本框广告 单页广告

    其中,文档描述信息不影响此次内容分析,暂不处理。剩余两类数据的清洗逻辑很简单,将在下一章介绍。

    2、数据清洗的准备工作

    就PowerPoint来说,已经提供了删除页面内文本框和删除Slide的接口。熟悉VBA的朋友(容易 暴露年龄)很容易在宏编辑中组织代码,进而在C++中实现完整逻辑。这次,我选择用python 实现,所有源码详见Git

    同时,我把VB代码在Git中也保留了一份,很方便您在宏编辑器中调试。

    2.1、关于MSOffice Interface Reference

    这部分的知识比较老,现在用的也不多。如果您刚接触,可以看我早先前在CSDN上的博 客——《北塔教你做插件》。如果只是查询接口,可以通过一下两个办法:

    方法1、MSOffice2010 帮助文件

    为什么不是其他版本?因为只有这个版本的帮助文件中提供了“开发人员参考”,点击“搜索”中的类型就可以找到。

    Office2010 帮助

    帮助文档提供的信息还是比较丰富的,除了接口说明还有很多例子,方便理解各个对象间的关系,是帮助理解、提高效率的利器。

    Shape详细信息

    方法2、MSO 接口声明
    我在Git中保存了MSO和MSPPT的接口声明,详见MSPPT_QuickReference目录

    如果您对VBA已经有些了解,且所使用的语言不是 C++的前提下,通过这两个文档查询接口与定义类型还是很方便的。比如,在Python中通过win32Com调用,所需的查询工作就可以在这两个文档中解决。

    准备工作就写到这,如果您还不太懂也没关系,进入下一章,我带您用python调用MSO接口,完成这40G文档的数据清洗。

    3、PPT文件的数据清洗

    创建COfficeAdapter的目的,就是为了封装MSO接口,以实现文件打开、操作和关闭等行为。为数据清洗和文档快照提供支持。

    源码如下:

    #!/usr/bin/python
    # -*- coding: gbk -*-
    
    '''''
    对MSOffice COM接口的封装,简单实现文件打开、操作和关闭等行为。
    为数据清洗和快照提供支持。
    '''
    
    import win32com  
    from win32com.client import Dispatch, constants  
    import os
    
    msoTrue = -1
    
    class COfficeAdapter():
        def __init__(self ):
            print "init"
            try:
                self.m_App = win32com.client.Dispatch('PowerPoint.Application')
                self.m_App.Visible = 1
            except BaseException:
                print "init Exception!!"
            #隐式加载为0 ,显式加载为1
    
        def __del__(self):
            print "__del__"
            try:
                self.m_App.Quit()
            except BaseException:
                print "Quit Exception!!"
    
    
        def OpenDoc(self, oPath):
            oRet = False
            if os.path.exists(oPath):
                oPath = oPath.lower()
                oNameSplit = os.path.splitext(oPath)
                if (oNameSplit[1] == ".ppt" or oNameSplit[1] == ".pptx"):
                    try:
                        self.m_Doc = self.m_App.Presentations.Open(oPath)
                        oRet = True
                    except BaseException:
                        print "OpenDoc Exception!!"
    
            return oRet
    
        def SaveDoc(self, newfilename=None):
            if newfilename:       
                self.m_Doc.SaveAs(newfilename)                  
            else:   
                oRet = self.m_Doc.Save()
                print "save:" ,oRet
    
        def CloseDoc(self):
            #print self.m_Doc.Saved
            try:
                self.m_Doc.Close()
            except BaseException:
                print "Close Exception!!"
    
    
        # 删除文档中恶意广告信息,只要包含制定字符,即删除整个textRange。
        # 此方法,主要针对"www.1ppt.com"。
        # 有删除操作返回true
        def RemoveTextRange(self, oKeyStr):
            oRet = False
            oSlideCounts = self.m_Doc.Slides.Count
            #遍历每一页,方便对每页数据进行操作
            for i in range(1 , oSlideCounts + 1):
                #print i ,"页"
                oSlide = self.m_Doc.Slides.Item(i)
                oShapeCounts = oSlide.Shapes.Count
                #print oShapeCounts
                #遍历单页中所有shape
                for j in range(1,oShapeCounts + 1):
                    oShape = oSlide.Shapes.Item(j)
                    #判断类型,找到文字
                    if oShape.TextFrame.HasText == msoTrue:
                        oTR = oShape.TextFrame.TextRange
                        try:
                            #oTextLen = oTR.Length
                            sText = oTR.Text
                            #转换为小写
                            sText = sText.lower()
                            #print sText
    
                            # 查找关键字,确认删除制定信息。
                            # 该方法并不用于最后一页,因为最后一页为整页的广告信息
                            oPos = sText.find(oKeyStr)
                            if oPos > 0  and i != oSlideCounts :
                                print "remove textRange" , i ,"+" ,oSlideCounts
                                oRet = True
                                oShape.Delete()
                                break
                            
                            if oPos > 0  and i == oSlideCounts :
                                print "delete Slide"
                                oRet = True
                                oSlide.Delete()
                                break                       
    
                        except BaseException:
                            print "BaseException"
            return  oRet
    
    
    def testDoc():
        oFilePath = r"D:\pptSpider\PPTFile1\A版小学五年级下册语文PPT课件\2015语文A版语文五下《一双新鞋》ppt课件.pptx"
        oKeyWork = "www.1ppt.com"
        print oFilePath
        oDoc = COfficeAdapter()
        if oDoc.OpenDoc(oFilePath):
            oRem = oDoc.RemoveTextRange(oKeyWork)
            #只有当删除页面元素时,才进行文档保存操作
            if oRem:
                oDoc.SaveDoc()
            oDoc.CloseDoc()
    
    #testDoc()
    

    接口分类比较清楚,具体内容就不讲了,需要注意两点:

    • 异常处理。解析上万文档,什么类型都会遇到,就拿OpenDoc来说,含密码、需修复和 打开失败等,异常情况很多,如果要想让代码不崩不断,tryCatch是免不了的。
    • MSO接口中,对象的删除是需要重建索引才能起作用的。在一套循环检索中, obj.delete()之后对象删了,但索引item还有。这个特点需要大家逐一。
    关于多作业并行处理的优化方案

    目前的实现逻辑是单作业串行操作,虽然文档处理速度是很快的,但由于文档量级较高,352个板块,3万份文档,一台PC机一天也没跑完。不过索性没断,就继续跑吧,等到数据分析的时候再做优化。

    备注:

    文档有了,脏数据也清干净了,下一步就是依据这些文档进行分析。抓的点我列了一半,周末再琢磨琢磨,下周就能开始跑了。
    我争取尽快输出文档,和大家分享。同时,也欢迎各位提出自己的想法和意见。

    相关文章

      网友评论

          本文标题:二、数据清洗,对广告信息说不

          本文链接:https://www.haomeiwen.com/subject/kkcdpxtx.html