Wie ich Avito per SMS überwacht habe

Wie Sie wissen, erscheinen auf Avito Produkte von sehr guter Qualität und gleichzeitig sehr günstig. Aber sie erscheinen selten, hängen wenig da und verschwinden schnell.

Daher hatte ich eine Idee: Anstatt nach einem Dienst zu suchen, der die Anzeigen alle paar Minuten überprüft, und wenn für mich etwas Interessantes auftaucht, werden Sie benachrichtigt? Gleichzeitig ist es am besten, per SMS zu benachrichtigen, da ich sonst nicht immer umgehend E-Mails checke.

Google hat mehrere solcher Dienste herausgegeben, "nur" ab 3 Rubel pro SMS oder ab 4 Rubel pro Tag.

Am Ende habe ich beschlossen, selbst einen solchen Service zu schreiben, aber dazu später mehr ...

Zum Spaß habe ich mich für einen der Dienste angemeldet. Gestern überprüfte er alle 15 Minuten die Links und wenn sich etwas änderte, schickte er Benachrichtigungen an die Mail. Über SMS auf ihrer Website wurde beiläufig erwähnt, dass mail.ru mail SMS versenden kann. Es stellte sich heraus, dass mail.ru nur per Megaphon senden kann, aber ich habe es nicht einmal ... Und wenn Sie Beeline-MTS benötigen, hilft Ihnen der Service gerne gegen eine Gebühr weiter.

Ich stelle außerdem fest, dass ich seit langer Zeit einen sehr praktischen und kostenlosen Dienst verwendet habe , über den ich direkt am Hub geschrieben habe und über den Sie eine E-Mail mit einem bestimmten Betreff an ein bestimmtes Postfach senden können. Der Inhalt der E-Mail wird in Form von SMS an mich gesendet. Ich wollte my_yaschik@sms.ru für Servicebriefe angeben, wusste aber nicht, wie ich den Betreff des Briefes ändern soll, ohne den Sie keine SMS erhalten.

Außerdem ist heute die Demo-Phase von glis beendet und die Überprüfungshäufigkeit beträgt 720 Minuten.

Wenn ich darüber nachdenke, wofür ich bezahlen soll, bedaure ich, dass ein "Dienst" dieser Art dem Bezahlen von Windows für Luft gleichkommt, entschied ich, dass der einfachste Weg darin besteht, 3 Stunden meiner wertvollen Zeit damit zu verbringen, einen solchen Dienst selbst zu erstellen, da das Parsen der Avito-Seite trivial und einfach ist hat mir wie folgt genau 1 zeile code abgenommen.

Ich habe für dieses Skript VPS-Hosting verwendet. WEB-Hosting ist ebenfalls geeignet, vorausgesetzt, es gibt eine Perle, einen Zugang von außen und einen Planer. In extremen Fällen ist jeder im Internet enthaltene Computer geeignet. Ich denke, viele haben etwas Ähnliches.

Worauf ist das Drehbuch geschrieben?


Ich habe beschlossen, es auf die Perle zu schreiben, und obwohl ich die Perle eher mittelmäßig kenne, ist sie am besten für Skripte dieser Art geeignet. Wo es zu faul war, mit der Perle umzugehen, habe ich mich nicht wirklich angestrengt, ich habe den Shell-Befehl durch das System gerufen. Trotzdem hat es sich meiner Meinung nach als ziemlich gut herausgestellt und ich zögere nicht, meine Kreation der Öffentlichkeit zu zeigen.

Die Logik der Arbeit, kurz


- Führen Sie das Skript alle xxx Minuten aus.
- Laden Sie die Seite mit wget herunter;
- Wir speichern die zuletzt heruntergeladene Seite und vergleichen sie mit der neu heruntergeladenen, wenn sich Ankündigungen geändert haben / neue erschienen sind - wir senden eine SMS darüber.

Die Informationen, die aus Anzeigen abgerufen werden, sind:

1. URL der Anzeige (die ich als eindeutige Kennung für die Anzeige verwende);
2. Name;
3. Preis.

Gleichzeitig ist vorgesehen, dass bei einem plötzlichen Absturz des Herunterladens einer Seite die alte Liste erhalten bleibt und die Seite nur beim nächsten Herunterladen heruntergeladen wird. In diesem Fall werden die Änderungen per SMS wirksam.

Detaillierter


Überprüfen Sie vor der Verwendung die Pfade und Namen für Mailer und Wget, stellen Sie sicher, dass Sie sie haben und arbeiten. Insbesondere mein Centos Mailer heißt Mutt, Mail oder Sendmail, wobei die gleiche Syntax gebräuchlicher ist. Möglicherweise müssen Sie wget durch / usr / local / bin / wget usw. ersetzen.

Sie sollten auch Ihre Mailbox und Ihr Telefon so einstellen, dass Sie Benachrichtigungen erhalten möchten.

Führen Sie das Skript mit folgendem Befehl aus: ./avito.pl url_pages_with_adverts.

Ich stelle fest, dass die URL der Seite in Form einer "Liste mit Fotos" vorliegen sollte. Mit anderen Worten, die URL sollte keine & view = list oder & view = gallery enthalten.

Beispiel-URL: www.avito.ru/moskva?q=%D1%80%D0%B5%D0%B7%D0%B8%D0%BD%D0%BE%D0%B2%D1%8B%D0%B9+% D1% 81% D0% BB% D0% BE% D0% BD

Seite heruntergeladen in einer Datei , die von Urla genannt, unter anderem der Ablösung aller Zeichen auf der linken Unterstrichen, wie folgt aus :

https ___ www.avito.ru_moskva_q__D1_80_D0_B5_D0_B7_D0_B8_D0_BD_D0_BE_D0_B2_D1_8B_D0_B9__D1_81_D0_BB_D0_BE_D0_BD

Es muss eindeutig sein, und in Linux und Windows und noch sein gut lesbar unterstützt werden.

Wenn eine solche Datei bereits vorhanden ist, versucht das Skript, Anzeigen daraus zu ziehen. Wenn in der Datei keine Anzeigen gefunden werden, ruft das Skript wget auf, während die Datei überschrieben wird. Wenn die Anzeigen gefunden werden, wird die Datei mit der Endung gespeichert -1:

https ___ www.avito.ru_moskva_q__D1_80_D0_B5_D0_B7_D0_B8_D0_BD_D0_BE_D0_B2_D1_8B_D0_B9__D1_81_D0_BB_D0_BE_D0_BD-1

Nächste Seite erneut heruntergeladen wird, werden die folgenden Situationen in verifiziert:

1. Wenn auf der neu heruntergeladenen Seite keine Anzeigen gefunden werden, wird das Skript einfach beendet - die alte Seite bleibt mit dem Suffix -1 erhalten. In diesem Fall ist das Netzwerk plötzlich verschwunden oder hängt - die Liste der Anzeigen in der Vergangenheit geht nicht verloren.
2. Wenn das Skript zum ersten Mal ausgeführt wird (die zuvor heruntergeladene Seite wurde nicht gefunden), wird in der Info einfach die Anzahl der verfügbaren Anzeigen angegeben:
25 gefundene Artikel, Seite www.avito.ru/moskva?q=%D1%80%D0%B5%D0%B7%D0%B8%D0%BD%D0%BE%D0%B2%D1%8B%D0% B9 +% D1% 81% D0% BB% D0% BE% D0% BD- Überwachung gestartet

Wenn diese Nachricht kam, dann startete das System, es ist hauptsächlich eine Überprüfung, dass alles funktioniert hat.

Da SMS umso kürzer sein sollten, desto besser sind dann alle Nachrichten sehr prägnant.

3. Wenn eine neue Ansage erschienen ist, werden die Informationen dazu in den Text der zukünftigen SMS eingefügt. Dann wird infa für alle Anzeigen in Form einer SMS gesendet.
4. Wenn sich der Preis oder der Name des Produkts geändert hat, hat die Information die Form: alter_Preis -> neuer_Preis-Namenslink. Oder new_name link.

Ich weiß nicht, ob sich der Name ändern kann, aber es war nicht schade, einen zusätzlichen Scheck zu machen.

5. Eine Liste der gefundenen Elemente wird in der Konsole in einem separaten Text angezeigt. Dies geschieht mehr zum Debuggen, da der Parser heute arbeitet und morgen, wenn er das Markup ändert, aufhört. Muss das Parsen ändern.

Über Parsing und Nuancen


Eigentlich ist alles Parsen in dieser Zeile:

while($text=~/

Der Preis enthält jedoch auch ein Leerzeichen in Form von nbsp, das ich mit einem anderen regulären Ausdruck ausgeschnitten habe:

$price=~s/ //g

Formal gesehen besteht das Parsen also immer noch nicht aus einer, sondern aus zwei Zeilen.

g - globaler Suchmodifikator, mit dem Sie die Suche in die while-Bedingung einfügen und jedes Mal die nächste Deklaration angeben können;
s - Ermöglicht die Suche in mehreren Zeilen innerhalb eines regulären Ausdrucks (bei Avito-URL sind Name und Preis in vier Zeilen angegeben, bis sie das Layout ändern).

Ich stelle auch fest, dass zum mehrzeiligen Lesen der Datei am Anfang des Skripts folgendes festgelegt ist:

undef $/;

Dies ist so, dass mein $ text =; Lesen Sie die gesamte Datei.

Eine weitere Nuance: Ich füge anklickbare URLs in alle SMS ein. Ich habe ein normales Smartphone, mit dem ich die URL in SMS stecken und auf die gewünschte Seite gelangen kann, sehr bequem. Aus irgendeinem Grund verdirbt sms.ru so einen unschuldigen Charakter wie Unterstrich. Ersetzen durch% C2% A7. Ich kann dies nicht beeinflussen, aber ich kann es durch einen Unterstrichcode ersetzen, der normalerweise angezeigt wird, während die URL für sms.ru anklickbar wird und für normale E-Mails dieselbe bleibt: $ text = ~ s / _ /% 5F / g;

Fügen Sie dem Scheduler eine Aufgabe hinzu


#crontab -e
*/20    *       *       *       *       cd /scripts/avito && ./avito.pl 'https://www.avito.ru/moskva?q=%D1%80%D0%B5%D0%B7%D0%B8%D0%BD%D0%BE%D0%B2%D1%8B%D0%B9+%D1%81%D0%BB%D0%BE%D0%BD'

Rufen Sie alle 20 Minuten das Skript auf und überprüfen Sie die Seite. Denken Sie daran, die URL in einfache Anführungszeichen zu setzen.

Sie können so viele Aufgaben stellen, wie Sie möchten. Alle Aufgaben funktionieren unabhängig voneinander.

Was ich für die industrielle Option nicht getan habe und was einfach zu vervollständigen wäre


1. Webface zum Hinzufügen / Entfernen von Benutzern und Aufgaben. Speicher-URLs, Häufigkeit, Mailbox- und Telefonbenutzer auf sms.ru in der MySQL-Datenbank. Das Skript wird jede Minute aufgerufen, überprüft, welche URL ausgeführt werden soll, und sendet SMS nicht an meine fest codierte Nummer, sondern an die vom Benutzer festgelegte.

Dann wäre es möglich, Benutzer bei 8 Rubel pro Tag oder so etwas abzureißen. Vielleicht, um es zu tun? Möchte jemand für so etwas bezahlen?

2. Preisfilter. Ignorieren Sie den Preis über oder unter dem festgelegten Preis. Es wird elementar noch eins getan if: next if($page_new{"price"}{$uri}>$max_price or $page_new{"price"}{$uri}<$min_price). Es musste einfach nicht.

3. Fügen Sie analog zu Avito auto.ru, irr usw. hinzu. Websites.

Es ist auch elementar, while(...){...}fügen Sie einfach ein paar mehr hinzu while- eine für jede Site. Die Hauptsache ist, dass sie innen gefüllt sind $page{"name"}{$uri} и $page{"price"}{$uri}.

Jede Site löst ihre eigene aus while, der Rest gibt nur ein leeres Ergebnis zurück.

Nun, eigentlich der Skriptcode


#!/usr/bin/perl
use strict;
undef $/;
my $url=$ARGV[0];
my $mailer="mutt";
my $wget="wget";
if($url eq ""){
    print "Usage: avito.pl ";
    exit;
}
my $filename=$url;
$filename=~s#[^A-Za-z0-9\.]#_#g;
$url=~m#(^.*?://.*?)/#;
my $site=$1;
print "site:".$site."\n";
sub sendsms {
    my $text=shift;
    $text=~s/_/%5F/g;
    $text=~s/&/%26/g;
    system("echo '$text' | $mailer -s 79xxxxxxxxx xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\@sms.ru");
}
sub parse_page {
    open(MYFILE,"<".shift);
    my $text=;
    close(MYFILE);
    my %page;
    while($text=~/

\n(.*?)\n.*?
\n\s*(\S*)/gs) { my $uri=$1; my $name=$2; my $price=$3; $uri=~s/^\s+|\s+$//g; $name=~s/^\s+|\s+$//g; $price=~s/^\s+|\s+$//g; $price=~s/ //g; $page{"name"}{$uri}=$name; $page{"price"}{$uri}=$price; } return %page; } my %page_old=parse_page($filename); if(scalar keys %{$page_old{"name"}}>0){ system("cp $filename ${filename}-1"); } else{ %page_old=parse_page("${filename}-1"); } system("$wget '$url' -O $filename"); my %page_new=parse_page($filename); if(scalar keys %{$page_old{"name"}}>0){ # already have previous successful search if(scalar keys %{$page_new{"name"}}>0){ # both searches have been successful my $smstext=""; foreach my $uri(keys %{$page_new{"name"}}) { if(!defined($page_old{"price"}{$uri})){ $smstext.="New: ".$page_new{"price"}{$uri}." ".$page_new{"name"}{$uri}." $site$uri\n "; } elsif($page_new{"price"}{$uri} ne $page_old{"price"}{$uri}){ $smstext.="Price ".$page_old{"price"}{$uri}." -> ".$page_new{"price"}{$uri}." ".$page_new{"name"}{$uri}." $site$uri\n"; } if(!defined($page_old{"name"}{$uri})){ # already done for price } elsif($page_new{"name"}{$uri} ne $page_old{"name"}{$uri}){ $smstext.="Name changed from ".$page_old{"name"}{$uri}." to ".$page_new{"name"}{$uri}." for $site$uri\n"; } } if($smstext ne ""){ sendsms($smstext); } } else{ # previous search is successful, but current one is failed # do nothing, probably a temporary problem } } else{ # is new search if(scalar keys %{$page_new{"name"}}<=0){ # both this and previous have been failed sendsms("Error, nothing found for page '$url'"); } else{ # successful search and items found sendsms("Found ".(scalar keys %{$page_new{"name"}})." items, page '$url' monitoring started"); } } foreach my $uri(keys %{$page_new{"name"}}) { print "uri: $uri, name: ".$page_new{"name"}{$uri}.", price: ".$page_new{"price"}{$uri}."\n"; if($page_new{"price"}{$uri} eq $page_old{"price"}{$uri}){print "old price the same\n";} else{print "old price = ".$page_old{"price"}{$uri}."\n";} if($page_new{"name"}{$uri} eq $page_old{"name"}{$uri}){print "old name the same\n";} else{print "old name = ".$page_old{"name"}{$uri}."\n";} }


Jetzt auch beliebt: