Das Skript muss ein Textfile checken ob es duplicate links gibt

  • Hi Powercoder :)

    Ich habe hier ein kleines crawler script. Das aus einer Textdatei mit urls jede einzelne url besucht und checkt ob es neue links auf der jeweiligen url gibt. Das Skript muss ein Textfile checken ob es duplicate links gibt - das file ist im Moment 20 MB und jeden tag wirds grösser -> je grösser das textfile desto langsamer wird das ganze. hat jemand eine idee um das schneller zu machen?
    :thumbup:

    Spoiler anzeigen
    [autoit]


    #Region ;**** Directives created by AutoIt3Wrapper_GUI ****
    #AutoIt3Wrapper_UseX64=n
    #AutoIt3Wrapper_Res_Fileversion=0.0.0.17
    #AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
    #AutoIt3Wrapper_Add_Constants=n
    #AutoIt3Wrapper_AU3Check_Stop_OnWarning=y
    #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
    #Include <File.au3>
    #include <IE.au3>
    #include <Array.au3>
    #include <string.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;Options
    Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase
    Opt("WinSearchChildren", 1) ;0=no, 1=search children also
    Opt("WinTextMatchMode", 1) ;1=complete, 2=quick
    Opt("WinWaitDelay", 250)
    Opt("WinDetectHiddenText", 1) ;1=on
    Opt("MouseCoordMode", 0)

    [/autoit] [autoit][/autoit] [autoit]

    $testurl = "www.google.de"
    $sites = FileOpen("rlinksites.txt", 0)
    $savepath=("rlinkurls.txt")
    $temppath=("True")
    $log = ("old_links_log.txt")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    FileDelete($savepath)
    FileDelete($temppath)

    [/autoit] [autoit][/autoit] [autoit]

    Local $hTimer = TimerInit() ; Begin the timer and store the handle in a variable.

    [/autoit] [autoit][/autoit] [autoit]

    Sleep(5000)

    [/autoit] [autoit][/autoit] [autoit]

    ; Check if file opened for reading OK
    If $sites = -1 Then
    ;MsgBox(0, "Error", "Unable to open file.")
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ; Read in lines of text until the EOF is reached
    While 1

    [/autoit] [autoit][/autoit] [autoit]

    ; Timer to know how long it takes to get all sites done
    ;$AnfangsTimer = TimerInit()

    [/autoit] [autoit][/autoit] [autoit]

    ; -------------------------------------------------------------------------
    ; Test if Internet available

    [/autoit] [autoit][/autoit] [autoit]

    Do
    MsgBox(4096, "Testing...", "...Internet Connection", 2)
    $testsite = 0
    $testsite = Ping($testurl)
    $e = 0
    While $testsite = 0
    If $e >= 10 Then Exit
    $testsite = Ping($testurl)
    MsgBox(4096, "No...", "...Connection - Try again",2)
    $e = $e + 1
    MsgBox("",$e,"",1)
    Sleep(1000)
    WEnd
    Until $testsite > 0
    MsgBox("","Internet is...","...Working",2)
    $e = 0
    ; -------------------------------------------------------------------------
    $line = FileReadLine($sites)
    If @error = -1 Then ExitLoop
    If $line = "" Then ContinueLoop ;skip blank lines
    $line = _IECreate($line)
    _IEErrorHandlerRegister ("MyErrFunc")
    If @error = -1 Then ContinueLoop
    Sleep(500)
    WinWait("Windows Internet Explorer","")
    WinSetState("Windows Internet Explorer", "", @SW_MAXIMIZE)
    If Not WinActive("Windows Internet Explorer","") Then WinActivate("Windows Internet Explorer","")
    WinWaitActive("Windows Internet Explorer","")
    Sleep(5000)
    If @error = -1 Then ContinueLoop
    ; $line = FileReadLine($sites)
    ; If @error = -1 Then ExitLoop
    ; If $line = "" Then ContinueLoop ;skip blank lines

    [/autoit] [autoit][/autoit] [autoit]

    $oLinks = _IELinkGetCollection ($line)
    $iNumLinks = @extended
    ;MsgBox(0, "Link Info", $iNumLinks & " links found")
    If @error = -1 Then ContinueLoop
    Dim $arLinks[1] = [$iNumLinks]

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $oLinks =_IELinkGetCollection($line)
    $iNumLinks = @extended

    [/autoit] [autoit][/autoit] [autoit]

    For $oLink in $oLinks
    $fileContent = FileRead($log)
    If NOT StringRegExp($fileContent, $olink.href) Then
    _ArrayAdd($arLinks, $oLink.href)
    ; Else
    ;; Do what you want with the link here
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _IEErrorHandlerRegister ("MyErrFunc")
    If @error = -1 Then ContinueLoop
    ;_ArrayDisplay($arLinks,"Links")
    ;if @error Then Msgbox(0,"", @error)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;If FileExists($savepath) Then
    ; FileDelete($savepath)
    ; EndIf
    ;_FileCreate($savepath)

    [/autoit] [autoit][/autoit] [autoit]

    ;_FileWriteToLine($savepath, 1, $arLinks[0], 0)

    [/autoit] [autoit][/autoit] [autoit]

    ;_FileWriteFromArray($writeurls, $arLinks, 1)

    [/autoit] [autoit][/autoit] [autoit]

    $writeurls = FileOpen($savepath=("rlinkurls.txt"),1)
    _FileWriteFromArray($writeurls, $arLinks, 1)
    FileClose($writeurls)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _IEQuit($line)
    If @error = -1 Then ContinueLoop

    [/autoit] [autoit][/autoit] [autoit]

    ; NEW
    Send("{ENTER}")
    ProcessClose("iexplore.exe")
    Sleep(1000)
    ProcessClose("iexplore.exe")
    Sleep(1000)
    ProcessClose("iexplore.exe")
    Sleep(1000)
    ProcessClose("wmplayer.exe")
    Sleep(1000)
    ProcessClose("msinm.exe")
    Wend

    [/autoit] [autoit][/autoit] [autoit]

    ; REMOVE DUPLICATE LINKS

    [/autoit] [autoit][/autoit] [autoit]

    Dim $oFile,$nFile

    [/autoit] [autoit][/autoit] [autoit]

    _FileReadToArray($temppath,$oFile)
    $nFile = _ArrayUnique($oFile)
    _FileWriteFromArray($savepath,$nFile)

    [/autoit] [autoit][/autoit] [autoit]

    ; Wire "old" URLS in log so they will be no more "double or more checking of same links"
    $savepath=("rlinkurls.txt")
    $log=("old_links_log.txt")

    [/autoit] [autoit][/autoit] [autoit]

    Dim $fileAll
    Dim $lastFile

    [/autoit] [autoit][/autoit] [autoit]

    $lastFile = 1 ;This is the number that is on the last file. Ex.
    ;You have work1.txt thru work11.txt then $lastFile
    ;should be 11.

    [/autoit] [autoit][/autoit] [autoit]

    $fileAll = FileOpen($log, 1) ;Write mode = Append to end of file.

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $lastFile Step 1
    FileWrite($fileAll, FileRead($savepath))
    Next

    [/autoit] [autoit][/autoit] [autoit]

    FileClose($fileAll)

    [/autoit] [autoit][/autoit] [autoit]

    ; NEW
    Send("{ENTER}")
    ProcessClose("iexplore.exe")
    Sleep(1000)
    ProcessClose("iexplore.exe")
    Sleep(1000)
    ProcessClose("iexplore.exe")
    Sleep(1000)
    ProcessClose("wmplayer.exe")
    Sleep(1000)
    ProcessClose("msinm.exe")

    [/autoit] [autoit][/autoit] [autoit]

    Local $iDiff = TimerDiff($hTimer) ; Find the difference in time from the previous call of TimerInit. The variable we stored the TimerInit handlem is passed as the "handle" to TimerDiff.

    [/autoit] [autoit][/autoit] [autoit]

    MsgBox(4096,"Execution Time",$iDiff)

    [/autoit] [autoit][/autoit] [autoit]

    Func MyErrFunc()
    ; Important: the error object variable MUST be named $oIEErrorHandler
    $ErrorScriptline = $oIEErrorHandler.scriptline
    $ErrorNumber = $oIEErrorHandler.number
    $ErrorNumberHex = Hex($oIEErrorHandler.number, 8)
    $ErrorDescription = StringStripWS($oIEErrorHandler.description, 2)
    $ErrorWinDescription = StringStripWS($oIEErrorHandler.WinDescription, 2)
    $ErrorSource = $oIEErrorHandler.Source
    $ErrorHelpFile = $oIEErrorHandler.HelpFile
    $ErrorHelpContext = $oIEErrorHandler.HelpContext
    $ErrorLastDllError = $oIEErrorHandler.LastDllError
    $ErrorOutput = ""
    $ErrorOutput &= "--> COM Error Encountered in " & @ScriptName & @CR
    $ErrorOutput &= "----> $ErrorScriptline = " & $ErrorScriptline & @CR
    $ErrorOutput &= "----> $ErrorNumberHex = " & $ErrorNumberHex & @CR
    $ErrorOutput &= "----> $ErrorNumber = " & $ErrorNumber & @CR
    $ErrorOutput &= "----> $ErrorWinDescription = " & $ErrorWinDescription & @CR
    $ErrorOutput &= "----> $ErrorDescription = " & $ErrorDescription & @CR
    $ErrorOutput &= "----> $ErrorSource = " & $ErrorSource & @CR
    $ErrorOutput &= "----> $ErrorHelpFile = " & $ErrorHelpFile & @CR
    $ErrorOutput &= "----> $ErrorHelpContext = " & $ErrorHelpContext & @CR
    $ErrorOutput &= "----> $ErrorLastDllError = " & $ErrorLastDllError
    ;MsgBox(0,"COM Error", $ErrorOutput)
    Return
    EndFunc ;==>MyErrFunc

    [/autoit]

    "Thinking in binary"

  • "Schneller" !?
    Wenn du eine Datei hast die 20MB gross ist, das Script jeden Link besuchen muss, dort checken ob neue links verfügbar sind...
    Das pro Zeile...
    Also schnell wird das in dieser Grösse niemals werden...

    Es wäre nur eine Möglichkeit, den 1. Link zu verfolgen, die File einzulesen, daraus einen MD5-Hash zu erstellen und den zu speichern.
    Entspricht der neue MD5 dann nicht dem alten, muss die Seite neu auf Links gescannt werden, da sich wohl etwas geändert hat...

    Jedoch denk mal nach, 20MB, jeder einzelne Link muss abgefragt werden... alleine schon das dauert ewig...
    dann noch jede Seite auf neue Links überprüfen...
    Das kann pro Abfrage schon gut 15 Sekunden dauern...

  • Das script lädt zeile für zeile von einem nicht sich änderten Textfile. Sind ca. 30 URLs. Auf jeder URL checkt das script ob neue links da sind. Falls ja haut er die URL in die 20 MB log datei und speichert nur die neuen gefundenen links in einer neuen textdatei.

    Das Bottleneck an Zeit ist hier ganz klar das testen ob die neuen links schon in der log datei sind.

    Warum benutze ich überhaupt eine log datei? Damit das Script weiss dass diese links schon besucht wurden.

    Hat jemand eine Idee das schneller zu machen?

    "Thinking in binary"

  • An einem WebCrawler hab ich mich auch schon mal versucht: Hab 3 mal alles hin geschmissen und nach nem halben Jahr wieder komplett neu angefangen... :whistling: Naja was ich dir aber empfehlen würde ist folgendes: Benutz nicht den IE um einen WebCrawler zu schreiben! :D Benutz entweder INetGet() oder die WinHTTP-Funktionen... (Letztere währen wohl am sinnvollsten) Außerdem würde ich dir raten den Quellcode mit StringRegExp zu löchern. ;) Und wenn du dann deinen WebCrawler vollendet hast wirst du feststellen, dass er vieeeeel zu langsam arbeiten wird... ;) Das liegt dann aber nicht an dir, sondern an Autoit allgemein. Naja das war jetzt mal meine Meinung zu dem Thema wenn du das anders siehst, dann ignoriere meinen Post einfach... :P

    LG
    Christoph :)

  • Die Liste in der sich die 1. Linmks befinden ist also nicht so gewaltig riesig?
    Ich würde empfehlen die gefundenen Links im Aufbau einer INI-File anzulegen...
    Wird der Wert dort gefuinden ist der Link schon vorhanden... Das ist insofern schneller weil man direkt an die Sprungmarke hüpfen kann, ist sie nicht vorhanden dann Link auch noch nicht in der Liste...

    Wieviele Links werden ca. auf den zu überprüfenden Siten sein?

    Das wird dann doch nicht so langsam wie erwartet ;)

    ABer ich glaube es gab da mal ne gewisse grenze der Filegrösse für INI-Files... kann mich aber auch täuschen...

    Das wäre dann recht leicht zu realisieren...

  • Nein, die Liste in der die Source Websites sind ist 20 Zeilen. Jede Zeile ein URL.

    Aber aus dieser Liste wird ja nach neuen Links geschaut.... Das können max. 30 neue links sein... und diese z.b. 30 links müssen gecheckt werden gegen eine log datei ob das neue links sind oder links sind die schon gefunden wurden.

    ini oder hash?

    Falls einer ne lösung hat bitte code zeigen! :wacko:

    "Thinking in binary"

  • Also ich habe es mir jetzt nicht sehr genau angesehen und könnte das Problem falsch verstanden haben,
    aber mit InetRead solltest du schneller vorankommen, als mit den _IE-Funktionen.

  • Nehmen wir an die es werden im Verlgeich mit der Logdatei neue Links gefunden, was soll dann passieren?
    Man könnte ja einfach nur die Links in die Logdatei schreiben und darauf achten das sie eben nie doppelt sind...
    Oder hast du mit den neuen Links iwas bestimmtes vor?
    Geht es rein dyrum nur eine Logdatei mit den Links zu erstellen, inwelcher aber eben keine doppelten Links vorkommen sollen?

  • Nehmen wir an die es werden im Verlgeich mit der Logdatei neue Links gefunden, was soll dann passieren? -> das ist ja der Punkt -> nur die neuen links in eine datei

    + alle alten und neuen in eine andere datei damit der crawler nicht links extrahiert die er ja schon "gemacht" hat

    HELP!!


    Ich denke es wäre schneller dass jede URL ein textfile mit den frischen links hat (URL-X-FRESH.txt) und dann die schon erledigten (URL-X-LOG)
    Danach nutze ich URL-X-FRESH und parse meine info von den urls und dann gehts von vorne wieder los.

    "Thinking in binary"

  • 20 MB text durchsuchen muss ja ewig dauern... vielleicht gehts besser, wenn du die "rlinkurls" als SQLite Datenbank machst.
    Die Suche in einer Datenbank geht doch naturgemäß ziemlich flott, dafür sind die dinger schliesslich gemacht.

    Wer andern eine Bratwurst brät
    der hat ein Bratwurstbratgerät.

    Einmal editiert, zuletzt von ohforf (24. Mai 2012 um 21:49)

  • ja, aber wie? noch nie gemacht. bitte um hilfe. ich zahle 20 euro per paypal für so ein script! Bin verzweifelt. 5 Tage lang schon mit dem Scheiss!

    "Thinking in binary"

  • Ich hab da schon was gescripted, hast du skype oder so? das würd schneller gehn...

  • tja ich sehe schon das bekommt hier keiner hin bis auf einen (ich nicht). schade ich denke das wäre ein tolles Projekt mit verschiedenen Ansätzen geworden... :thumbdown:

    "Thinking in binary"

  • Kannst du mal einen Extrakt aus der Textdatei mit den Links posten? Ich würde gerne den Inhalt sehen, wie diese Datei aufgebaut ist.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Kannst ja mal dies probieren:

    Spoiler anzeigen
    [autoit]


    $timer = TimerInit()
    $aIPs = StringRegExp(FileRead(@ScriptDir & "\Links.txt"), "\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):\d+\s*", 3)
    ConsoleWrite("Datei einlesen und nach IPs filtern: " & Round(TimerDiff($timer), 4) & " ms." & @LF)
    ConsoleWrite(UBound($aIPs) & " IPs gefunden." & @LF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Doppelte Einträge aus dem Array entfernen..." & @LF)
    $timer = TimerInit()
    $aUnique = ArrayUnique($aIPs)
    ConsoleWrite("Laufzeit doppelte Einträge entfernen: " & Round(TimerDiff($timer), 4) & " ms." & @LF)
    ConsoleWrite(UBound($aUnique) & " IPs nach Lösung, falls doppelte gefunden." & @LF)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ============================================================================
    ; Name.............: ArrayUnique
    ; Description ...: Returns the Unique Elements of a 1-dimensional or 2-dimensional array.
    ; Syntax...........: _ArrayUnique($aArray[, $iBase = 0, oBase = 0])
    ; Parameters ...: $aArray - The Array to use
    ; $iBase - [optional] Is the input Array 0-base or 1-base index. 0-base by default
    ; $oBase - [optional] Is the output Array 0-base or 1-base index. 0-base by default
    ; Return values: Success - Returns a 1-dimensional or 2-dimensional array containing only the unique elements
    ; Failure - Returns 0 and Sets @Error:
    ; 0 - No error.
    ; 1 - Returns 0 if parameter is not an array.
    ; 2 - Array has more than 2 dimensions
    ; 3 - Array is already unique
    ; 4 - when source array is selected as one base but UBound(array) - 1 <> array[0] / array[0][0]
    ; 5 - Scripting.Dictionary cannot be created for 1D array unique code
    ; Author .........: UEZ 2010 for 2D-array, Yashied for 1D-array (modified by UEZ)
    ; Version ........: 0.96 Build 2010-11-20 Beta
    ; Remark ........: check is always case sensitive
    ; =======================================================================================
    Func ArrayUnique($aArray, $iBase = 0, $oBase = 0)
    If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;not an array
    If UBound($aArray, 0) > 2 Then Return SetError(2, 0, 0) ;array is greater than a 2D array
    If UBound($aArray) = $iBase + 1 Then Return SetError(3, 0, $aArray) ;array is already unique because of only 1 element
    Local $dim = UBound($aArray, 2), $i
    If $dim Then ;2D array
    If $iBase And UBound($aArray) - 1 <> $aArray[0][0] Then Return SetError(4, 0, 0)
    Local $oD = ObjCreate('Scripting.Dictionary')
    If @error Then Return SetError(5, 0, 0)
    Local $i, $j, $k = $oBase, $l, $s, $aTmp, $flag, $sSep = Chr(01)
    Local $aUnique[UBound($aArray)][$dim]
    If Not $oBase Then $flag = 2
    For $i = $iBase To UBound($aArray) - 1
    For $j = 0 To $dim - 1
    $s &= $aArray[$i][$j] & $sSep
    Next
    If Not $oD.Exists($s) And StringLen($s) > 3 Then
    $oD.Add($s, $i)
    $aTmp = StringSplit(StringTrimRight($s, 1), $sSep, 2)
    For $l = 0 To $dim - 1
    $aUnique[$k][$l] = $aTmp[$l]
    Next
    $k += 1
    EndIf
    $s = ""
    Next
    $oD.RemoveAll
    $oD = ""
    If $k > 0 Then
    If $oBase Then $aUnique[0][0] = $k - 1
    ReDim $aUnique[$k][$dim]
    Else
    ReDim $aUnique[1][$dim]
    EndIf
    Else ;1D array
    If $iBase And UBound($aArray) - 1 <> $aArray[0] Then Return SetError(4, 0, 0)
    Local $sData = '', $sSep = ChrW(160), $flag
    For $i = $iBase To UBound($aArray) - 1
    If Not IsDeclared($aArray[$i] & '$') Then
    Assign($aArray[$i] & '$', 0, 1)
    $sData &= $aArray[$i] & $sSep
    EndIf
    Next
    If Not $oBase Then $flag = 2
    Local $aUnique = StringSplit(StringTrimRight($sData, 1), $sSep, $flag)
    EndIf
    Return $aUnique
    EndFunc ;==>ArrayUnique

    [/autoit]


    Und diese Datei habe ich benutzt: autoit.de/wcf/attachment/15764/


    Gruß,
    UEZ

  • Hast du falsch verstanden:

    rlinksites.txt = ca. 100 websites mit dynamischen links zu proxies
    rlinks.txt = nur die frischen links speichern (auf denen proxies gepostet sind)
    old_links_log = frische links mit "alten" vergleichen und in die datein schreiben


    das heisst am ende wir haben viele frische urls mit proxies die dann mit regexp rausgefiltert werden müssen und dann eine IP.txt datei entsteht mit dem format:
    IP:Port
    IP:Port
    etc.

    :S

    "Thinking in binary"

    Einmal editiert, zuletzt von R4z0r (2. Juni 2012 um 00:01)