Mini-„Recap“ zur OTMR2019

Am 11. 10. besprach ich mit interessierten Teilnehmer_innen einige Aspekte der Arbeiten an den Datenbanksystemen rund um „InstaLoc2.0“.

Die Veranstaltung wurde von der sympathischen Kanzlei „Spirit Legal“ organisiert und meine anfängliche Skepsis (Inhalte, hoher Verkaufsdruck) wurde durch diverse Vorabgespräche und die Speakerliste beseitigt.

Aber nun zu den Eindrücken.

Die Veranstaltung startete mit einer Keynote von Glacier Kwong und hier wurde das interessierte Publikum über die aktuelle Situation in HongKong und Überwachungstendenzen seitens der staatlichen Obrigkeit(en) und Konzernen via Daten/BigData informiert. Obwohl die dargebotenen Informationen für mich (privat+geschäftlich) nicht neu waren, passte diese Keynote sehr gut. Der Grund ist: man muss permanent auch in der professionellen Benutzung und Verwertung der Plattformen auf die Gefahren des Mißbrauchs hinweisen.

Wegen meinem Interesse an u.a. konkreten Einsatzszenarien der Ergebnisse aus dem Feld der datengetriebenen Marktforschung schaute ich mir die Session von Petra Lukaschewski und Michael Benz an.

Michael Benz stellte in einem ca. 30 Minuten-Slot die Funktionsweise(n) und Logiken von „Whyapply“ vor. Es geht hierbei um eine besondere Form der Mitarbeiter_innen-Akquise via Einholen von groben Projektideen zwecks Vorabsichtung potentiell interessanter Köpfe. Soweit ich das System verstanden habe, veröffentlichen pot. Arbeitgeber_innen bei Whyapply eine besondere Form der Wettbewerbe um Ideen zur Lösung aktueller (Mini)probleme.

Petra Lukaschewski klärte das interessierte Publikum zum nachhaltigen Teamaufbau auf. Mich faszinierte hier, dass offensichtlich ein enormer Nachholebedarf beim Management konkreter Arbeits+Gehaltsverhandlungen existiert und die Gesprächspartner_innen gerade auch im Kampf um die besten Köpfe (offensichtlich) externe Hilfe zwingend notwendig eingekauft werden muss.

Ganz kurz schaute ich in den Vortrag von Dr. Jonas Kahl und Thomas Busch rein. Beide sprachen erstaunlich praxisnah über die Arbeit am Problem der Sperr- u. Löschpraxis von u.a. Tweets u. Twitteraccounts. Mir wurden hier einige Beispiele präsentiert und wir diskutierten auch über technische Muster und das Problem, dass engagierte Anwält_innen (leider) wenig Zugang zu uns Nerds haben. Vielleicht ergeben sich hier in den eventuellen Nachgesprächen weitere Kommunikationskanäle?

Fazit:

Wenn ich mir den üblichen Szene/Branche-Veranstaltungskatalog anschaue, sticht die OTMR durch den klaren Bezug auf einen richtigen Austausch von Expertenwissen hervor. Branchentypische Verkaufsgespräche entdeckte ich nicht und ich kann den Besuch dieser Veranstaltung definitiv empfehlen. Zielgruppen wären: Entscheidungsträger_innen aus sämtlichen Marketingsparten, Geschäftsführer_innen mit Bezug u./o. Entscheidungsbedarf rund um die Marketingstrategien und sämtliche Marketingdienstleister_innen inkl. Agenturen.

Ein Engagement bei der OTMR2020 ist für mich aktuell denkbar. :-)

Projekt „InstaLOC“ – Datenbankbefüllung auf Basis der Tagsuche

(1) Vorbereitung
Im ersten Schritt wird die Datenbank angelegt.

with sql_befehle do
begin
clear;
lines.Add('drop table if exists locations;');
lines.Add('CREATE TABLE `locations` (');
lines.Add(' `id` integer primary key AUTOINCREMENT,');
lines.Add('`url` varchar(400),');
lines.Add('`tag` varchar(2000),');
lines.Add('`likes` varchar(400),');
lines.Add('`comments` varchar(400),');
lines.Add('`erstellzeit` varchar(400),');
lines.Add('`post_id` varchar(1600),');
lines.Add('`username` varchar(400),');
lines.Add('`location` varchar(400),');
lines.Add('`filter` varchar(400),');
lines.Add('`pruefzeit` varchar(400)');
lines.Add(');');
lines.Add('vacuum;');
end;
fdquery3.ExecSQL(sql_befehle.text);

Die Datei umfasst folgende Spalten:
ID -> Nummerierung der Einträge (Zeilen)
URL -> erfasste Beitragsurl
Tag -> erfasste Tagwolke
Likes -> erfasste Likes als Zahl
Comments -> erfasste Comments als Zahl
Post_ID -> per Instagram vergebene Medien/Beitrags-ID
Username -> Username: Wer hat den Beitrag veröffentlicht?
Location -> Location des Beitrages, falls vom User freigegeben (GeoCode + Name)
Filter -> Fotofilter des veröffentlichten Beitrages
Erstellzeit -> Wann wurde der Beitrag veröffentlicht?
Pruefzeit -> Wann wurde der Beitrag vom Scraper erfasst UND in die Datenbank gespeichert?

(2) Scrapingvorgang
for lauf := strtoint(uebertrag.Text) to memo8.Lines.Count-1 do
begin
randomize;
token.Text:=token.Items[random(token.Items.Count-1)];
getmedia_db(locmedia,memo8.Lines[lauf],200);
end;

(3) Scrapingprozedur

procedure TForm1.getmedia_db(mytable: TStringGrid; tagsearch: string; rounds: integer);
var
JSONArray: tJSONArray;
JSONValue,jvalue: tJSONValue;
JSONPair: TJSONPair;
JSON, json_sub: TJSONObject;
size: integer;
j_array: tJSONArray;
s: string;
i,j: integer;
next_id: string;
zaehl: integer;
url,tag,likes,comments,post_id,username,location,filter,pruefzeit: widestring;
erstellzeit: string;
begin
sql_befehle.Clear;
memo3.Lines.Add('url => https://api.instagram.com/v1/tags/'+escape(tagsearch)+'/media/recent?access_token='+token.text);
try
debug.text:=idhttp1.Get('https://api.instagram.com/v1/tags/'+escape(tagsearch)+'/media/recent?access_token='+token.text);
JSONValue := TJSONObject.ParseJSONValue(debug.text);
JSON := TJSONObject.ParseJSONValue(debug.Lines.Text) as TJSONObject;
JSONArray := TJSONArray(JSON.Get('data').JsonValue);
try next_id:= JSONValue.GetValue('pagination.next_url');
except
next_id:='N/A';
end;
for i := 0 to JSONArray.Size - 1 do
begin
url:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('link')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('tags')).ToString);
s:= StringReplace(s, '"tags":[', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, ']', '', [rfReplaceAll,rfIgnoreCase]);
tag:=escape(s);
memo7.Lines.Add(unescape(tag));
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('likes')).ToString);
s:= StringReplace(s, '"likes":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
likes:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('comments')).ToString);
s:= StringReplace(s, '"comments":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
comments:=s;
erstellzeit:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('created_time')).JsonValue.Value);
erstellzeit:=datetimetostr(UnixToDateTime(strtoint(erstellzeit)));
post_id:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('id')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('user')).ToString);
s:= StringReplace(s, '"user":{"username":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '"', '', [rfReplaceAll,rfIgnoreCase]);
username:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('location')).ToString);
s:= StringReplace(s, '"location":', '', [rfReplaceAll,rfIgnoreCase]);
location:=s;
filter:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('filter')).JsonValue.Value);
pruefzeit:=datetimetostr(now);
with sql_befehle.Lines do
begin
add('INSERT INTO `locations` (`url`, `tag`, `likes`, `comments`, `erstellzeit`, `post_id`, `username`, `location`, `filter`, `pruefzeit`) Values ('''+url+''', '''+tag+''', '''+likes+''', '''+comments+''', '''+erstellzeit+''', '''+post_id+''', '''+username+''', '''+location+''', '''+filter+''', '''+pruefzeit+''');');
end;
end;
fdquery3.ExecSQL(sql_befehle.text);
sql_befehle.Clear;
except
end;
if next_id<>'N/A' then
begin
repeat
// -> tiefenpruefung
if next_id='N/A' then
break;
delay(strtoint(frequenz1.Text));
try
debug.text:=idhttp1.Get(next_id);
JSONValue := TJSONObject.ParseJSONValue(debug.text);
JSON := TJSONObject.ParseJSONValue(debug.Lines.Text) as TJSONObject;
JSONArray := TJSONArray(JSON.Get('data').JsonValue);
try next_id:= JSONValue.GetValue('pagination.next_url');
except
next_id:='N/A';
break;
end;
for i := 0 to JSONArray.Size - 1 do
begin
url:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('link')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('tags')).ToString);
s:= StringReplace(s, '"tags":[', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, ']', '', [rfReplaceAll,rfIgnoreCase]);
tag:=escape(s);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('likes')).ToString);
s:= StringReplace(s, '"likes":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
likes:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('comments')).ToString);
s:= StringReplace(s, '"comments":{"count":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
comments:=s;
erstellzeit:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('created_time')).JsonValue.Value);
erstellzeit:=datetimetostr(UnixToDateTime(strtoint(erstellzeit)));
post_id:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('id')).JsonValue.Value);
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('user')).ToString);
s:= StringReplace(s, '"user":{"username":', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '}', '', [rfReplaceAll,rfIgnoreCase]);
s:= StringReplace(s, '"', '', [rfReplaceAll,rfIgnoreCase]);
username:=s;
s:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('location')).ToString);
s:= StringReplace(s, '"location":', '', [rfReplaceAll,rfIgnoreCase]);
location:=s;
filter:=(TJSONPair(TJSONObject(JSONArray.Get(i)).Get('filter')).JsonValue.Value);
pruefzeit:=datetimetostr(now);
with sql_befehle.Lines do
begin
add('INSERT INTO `locations` (`url`, `tag`, `likes`, `comments`, `erstellzeit`, `post_id`, `username`, `location`, `filter`, `pruefzeit`) Values ('''+url+''', '''+tag+''', '''+likes+''', '''+comments+''', '''+erstellzeit+''', '''+post_id+''', '''+username+''', '''+location+''', '''+filter+''', '''+pruefzeit+''');');
end;
end;
fdquery3.ExecSQL(sql_befehle.text);
sql_befehle.Clear;
except
break;
end;
// -> tiefenpruefung, ende
zaehl:=zaehl+1;
until zaehl=rounds;
end;
end;

Prozeduraufruf.

getmedia_db(locmedia,memo8.Lines[lauf],200);

Erklärung, Prozedurlogik:

Die Variable „locmedia“ ist für das Szenarium relativ uninteressant und wird aktiviert, wenn bspw. die gescrapten Daten in ein Stringgridobjekt zwecks Gegensichtung übergeben werden müssen. Die Variable „memo8.lines[X]“ beschreibt den Zwischenspeicherort der Tagliste(n), wobei „X“ oder „lauf“ die Position des Terms / Tags in der Liste beschreibt. Die Variable „200“ sagt aus, wie tief die Scrapingprozedur forschen soll. In dem Fall handelt es sich um 200×20 (-> 4000) Beiträge je Suchanfrage.

[Notiz] Erste Ergebnisse aus dem Socialmediarecherche-Experiment

Im Zuge der Jahreswende und den bekannten G-Algo-Updatemeldungen baute ich die Ergebnisse aus der socialmediabasierten Zielgruppenrecherche an die Vermarktung eines unserer Experimente.
Im Prinzip handelt es sich hierbei um das vorgelagerte Auslesen von bestimmten Wertigkeiten (Reichweite von Tags, Kommunikationsfetzen usw.) für

Produkte
ortsbezogene Dienstleistungen
Orte und „Events“

und das Verwenden der Ergebnisse für die gezielte Promotion entsprechender Angebote aus einem Affiliateumfeld.
Die Zwischenergebnisse (Positionen, AUSZUG, Messung via Rankingchecker und Abgleich mit Piwik/WMT) sind nun:

  1. „köln deals“: N/A auf #19
  2. „mainz deals“: N/A auf #32
  3. „nürnberg deals“: N/A auf #44
  4. „bielefeld deals“: N/A auf #20
  5. „bonn deals“: N/A auf #21
  6. „halle deals“: N/A auf #16
  7. „braunschweig deals“: N/A auf #17
  8. „mannheim deals“: N/A auf #20
  9. „deals magdeburg“: N/A auf #21
  10. „dresden deals“: N/A auf #36

Die genannten Phrasen und deren Positionen sind stabil und bei dem Projekt handelt es sich um die Domain hinter dem Beitrag „„neues Affiliate-Projekt““ Die Provisionen haben sich ca. vervierfacht.