view Search.py @ 2:6d8b6a689b2b default tip

changed to bs4
author dwinter
date Mon, 15 Oct 2012 15:09:35 +0200
parents 57e2aa489383
children
line wrap: on
line source

'''
Created on 12.10.2012

@author: dwinter
'''
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey, DateTime, select
from query import CrawlerDb
import re
import logging
from BeautifulSoup import BeautifulSoup, Comment
import urllib2
try:
    from Products.PageTemplates.PageTemplateFile import PageTemplateFile
except:
    class PageTemplatefile:
        pass

try:
    from OFS.SimpleItem import SimpleItem
except:
    class SimpleItem:
        pass
class Search(SimpleItem):
    meta_type = 'SearchCrawler'
    def readPage(self,url):
        
        req = urllib2.Request(str(url))
        req.add_header('User-Agent', 'PyCrawler 0.2.0')
        request = None
        status = 0
        try:
            request = urllib2.urlopen(req)
        except urllib2.URLError, e:
            logging.error("Exception at url: %s\n%s" % (url, e))
            return None
        except urllib2.HTTPError, e:
            status = e.code
        if status == 0:
                status = 200
        data = request.read()
        
        return data
    def __init__(self):
        self._v_db=CrawlerDb()
        self._v_db.connect()
        
    
    def search(self,keyword):
        
        if getattr(self, "_v_db",None)==None:
            self.__init__();
        s = select([self._v_db.keyword_table]).where(self._v_db.keyword_table.c.keyword==keyword)
        ret=[]
        result = self._v_db.connection.execute(s)
        logging.debug(s)
        logging.debug(keyword)
        logging.debug(result)
        results= result.fetchall()
        logging.debug(results)
        
        for r in results:
            pid= r.page_id
            logging.debug(pid)
            s2 =select([self._v_db.crawl_table]).where(self._v_db.crawl_table.c.id==pid)
            resultPage = self._v_db.connection.execute(s2)
            for rp in resultPage.fetchall():
                ret.append((rp.address,rp.title))
              
                print self.getGetNeighbourhood(rp.address, keyword)
                
                
        return ret
                
    def getGetNeighbourhood(self,url, wordStr, length=100,tagging=True):
        """finde umgebung um die worte in wordStr, zurueckgegeben wird eine Array mit den Umgebungen von Fundstellen der Worte
        alle Tags werden entfernt, die Fundstellen werden mit <span class="found">XX</span> getaggt, die Umgebungen werden 
        case insensitive gesucht
        @param wordStr: string mit Worten getrennt durch Leerzeichen, Phrasen sind mit " gekennzeichnet
                        "eine phrase", "*"  bezeichnet wildcards und wird ignoriert"
        @param length: optional, default wert 100, 2*length ist die groesse der Umgebung
        @param tagging: optional default wert true, kein span tag wird erzweugt falls tag=false
        """
        
        ret=[] # nimmt das Array auf, dass spaeter zurueckgegeben wird
        ranges=[] #Array mit tupeln x,y wobei x die Position des Anfang und y des Endes der i-ten Umgebung angiebt
        
        wordStr=wordStr.lstrip().rstrip()
        
        def isInRanges(nr,length):
            """test ob eine gegeben Position nr schon irgendwo in einer Umgebung ist, gibt den Index des ersten Wertes aus ranges zurueck, 
            -1, wenn kein Treffer
            
            @param nr: Position die geprueft werden soll
            @param length: Laenge des Wortes das geprueft werden soll
            """
            for x in ranges:
                if (x[0]<=nr) and (nr < (x[1]-length)):
                    return ranges.index(x)
            return -1
                
        # deal with phrases, in Phrasen werden die Leerzeichen durch "_" ersetzt.
        def rep_empty(str):
            x= re.sub(" ","_",str.group(0))
            return re.sub("\"","",x)
            
        wordStr=re.sub("\".*?\"", rep_empty,wordStr)#ersetze leerzeichen in " " durch "_" und loesche "
        
        #deal with wildcards, for our purposes it is enough to delete the wildcard 
        wordStr=wordStr.replace("*","")
        
        words=wordStr.split(" ")
        #if not words is ListType:
        #   words=[words]
        
        
        txtCache = self.en.getHarvestCache();
        txt=  txtCache.get(url,None)
       
        txt=None       
        if txt==None:
            
            logging.debug("NO CACHE for: "+url)
            
            
            
            txt=self.readPage(url)
        
        
        if not txt:
            return ret
        
        soup = BeautifulSoup(txt)
        
        comments = soup.findAll(text=lambda text:isinstance(text, Comment))
        [comment.extract() for comment in comments]
        
        txt = ''.join(soup.findAll(text=True))
        
        
        #txt=re.sub("<.*?>", "", txt) # loesche alle Tags
        for word in words:
            word=re.sub("_"," ",word) # ersetze zurueck "_" durch " "
            pos=0
            
            n=txt.lower().count(word.lower()) # wie oft tritt das Wort auf

            for i in range(n):
                pos=txt.lower().find(word.lower(),pos)

                if pos > 0:
                    x=max(0,pos-length)
                    y=min(len(txt),pos+length)
                  
                    
                    #is word already in one of the results
                    nr=isInRanges(pos,len(word))
                    if nr >=0:# word ist in einer schon gefunden Umgebung, dann vergroessere diese
                        x=min(ranges[nr][0],x)
                        y=max(ranges[nr][1],y)
              
                    str=txt[x:y]
                    if x!=0: #add dots if in the middle of text
                        str="..."+str
                    
                    if y!=len(txt): #add dots if in the middle of text
                        str=str+"..."
                        
                        
                
                    if nr >=0: # word ist in einer schon gefunden Umgebung
                        ranges[nr]=(x,y) # neue Position der Umgebung

                        ret[nr]=str # neue Umgebung
                    else: # andernfalls neue Umgebung hinzufuegen
                        ranges.append((x,y))

                        ret.append(str)
                    
                    pos=pos+len(word)
                else:
                    break;
                
        # now highlight everything        
        if tagging:
            for x in range(len(ret)):
                for word in words:
                    repl=re.compile(word,re.IGNORECASE)
                    ret[x]=repl.sub(""" <span class="found">%s</span>"""%word.upper(),ret[x])

        return ret
            
def manage_addSearch(self,id,REQUEST):
    """ create the new MPIWGManager """
    newinst = Search()
    self._setObject(id, newinst)

    REQUEST.RESPONSE.redirect('manage_main')

try:
    manage_addSearchForm = PageTemplateFile('zpt/addSearch.pt',globals())
except:
    pass

if __name__ == '__main__':
    
    logging.getLogger().setLevel(logging.DEBUG)
    s = Search()
    print s.search("Kuhn")