UnicodeEncodeError beim Abspeichern von OnlineFeeds in MySQL

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Servus zusammen,

wer noch über keinen meiner zahlreichen Foreneintraege gestolpert ist: Aktuell versuche ich Feeds in einer MySQL Datenbank abzuspeichern, die ich zuvor von verschiedenen HP downloade. Mein Code funktioniert eigentlich, wirft mir aber folgenden Fehler aus:

UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026' in position 32: ordinal not in range(256)

Dieser Fehler kommt aber nicht automatisch sondern nach einiger Zeit (circa alle 6 Stunden und ich lade aktuell alle 4 Minuten eine Feedliste herunter). Bis zur Fehlermeldung funktioniert alles so wie es soll. Die Bedeutung des Fehlers ist mir vollkommen klar, was mir nicht klar ist, ist

1.) Wie kann ich den Fehler verhindern und wo genau vermutet ihr entsteht der Fehler?

2.) Kann ich eine Case in den Code einbauen, dass wenn dieser Fehler auftaucht, eine Fehlermessage ausgespuckt wird aber der Code dennoch wie gewohnt weiterarbeitet? Wenn ja habt ihr mir da ein Codebeispiel?

Hier ist mein aktueller Code:

Code: Alles auswählen

import feedparser
import urllib2
import cookielib
import MySQLdb
import time
import datetime
from cookielib import CookieJar
from urllib2 import urlopen


db = MySQLdb.connect(host="localhost", # your host, usually localhost
                 user="root", # your username - SELECT * FROM mysql.user
                 passwd="*****", # your password
                 db="sentiment_analysis") # name of the data base

cur = db.cursor()
cur.execute("DROP TABLE IF EXISTS feeddata_iii")
cur.execute("DROP TABLE IF EXISTS feeddata_lse")

sql_iii = """CREATE TABLE feeddata_iii (III_ID INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(III_ID),III_UnixTimesstamp integer,III_Timestamp varchar(255),III_Source varchar(255),III_Title             varchar(255),III_Text TEXT,III_Link varchar(255),III_Epic varchar(255),III_CommentNr integer,III_Author varchar(255))"""

sql_lse = """CREATE TABLE feeddata_lse (LSE_ID INT NOT NULL AUTO_INCREMENT,PRIMARY KEY(LSE_ID),LSE_UnixTimesstamp integer, LSE_Timestamp varchar(255), LSE_Source varchar(255), LSE_Title varchar(255), LSE_Text TEXT,  LSE_Link varchar(255), LSE_Epic varchar(255), LSE_CommentNr integer, LSE_Author varchar(255))"""

cur.execute(sql_iii)
cur.execute(sql_lse)

opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(CookieJar()))
opener.addheaders = [{'User-agent','Mozilla/5.0'}]

def feed_load_iii(feed_iii):
return [(time.time(),
         entry.published,
         'iii',
         entry.title,
         entry.summary,
         entry.link,
         (entry.link.split('=cotn:')[1]).split('.L&id=')[0],
         (entry.link.split('.L&id=')[1]).split('&display=')[0],
         entry.author)
        for entry
        in feedparser.parse(feed_iii).entries]

def feed_load_lse(feed_lse):
return [(time.time(),
         entry.published,
         'lse',
         entry.title,
         entry.summary,
         entry.link,
         (entry.link.split('?ShareTicker=')[1]).split('&post=')[0],
         entry.link.split('&post=')[1],
         entry.author)
        for entry
        in feedparser.parse(feed_lse).entries]

def main():
feed_url_iii = "http://www.iii.co.uk/site_wide_discussions/site_wide_rss2.epl"
feed_url_lse = "http://www.lse.co.uk/chat/recent/"

feed_iii = feed_load_iii(feed_url_iii)
feed_lse = feed_load_lse(feed_url_lse)

print 'Timestamp of first Comment in III Feed'
print feed_iii[1][1]
print 'Timestamp of first Comment in LSE Feed'
print feed_lse[1][1]
print 'Next Feed Load in 240 Seconds'
print '------------------------------'

for item in feed_iii:
    cur.execute("""INSERT INTO feeddata_iii(III_UnixTimesstamp, III_Timestamp, III_Source, III_Title, III_Text, III_Link, III_Epic, III_CommentNr, III_Author) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)""",item)
db.commit()

for item in feed_lse:
    cur.execute("""INSERT INTO feeddata_lse(LSE_UnixTimesstamp, LSE_Timestamp, LSE_Source, LSE_Title, LSE_Text, LSE_Link, LSE_Epic, LSE_CommentNr, LSE_Author) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)""",item)
db.commit()

if __name__ == "__main__":
while True:
    main()
    time.sleep(240)
Anfangs dachte ich es liegt an dem Print-Block im Code und daher habe ich folgendes ausprobiert:

Code: Alles auswählen

print feed_lse[1][1].encode('ascii', 'replace') 
Ergebnis: Fehler tritt weiterhin auf!

Da ich ein sehr sehr junger Programmierer bin, bitte ich euch, möglichst "einfach" zu antworten und dabei am besten mit Codebeispielen, damit ich verstehe was ihr meint 8)

Wie immer gilt: HERZLICHEN DANK!
BlackJack

@h0rnung: Da gehört doch noch ein Traceback dazu. So eine Meldung besteht ja nicht nur aus dieser letzten Zeile. Daran sieht man dann doch an welcher Quelltextzeile es kracht.

Ich vermute mal einfach das Du die Datenbankt so konfigurieren musst, dass sie Unicode als UTF-8 kodiert überträgt, und wohl am besten auch speichert.

Edit: Hast Du da zwei Tabellen mit der gleichen Struktur? Warum? Und warum haben die ganzen Spaltennamen in einer Tabelle nochmal den gleichen Präfix wie der Tabellenname? Das macht keinen Sinn.
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

@BlackJack abermals herzlichen Dank für deine schnelle Antwort. Musst mir bald mal deine Kontodetails zukommen lassen wenn das so weiter geht :oops:

Hier der Traceback

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Python27\MySQL_finalversion\RSS_III_FV.py", line 51, in <module>
    main()
  File "C:\Python27\MySQL_finalversion\RSS_III_FV.py", line 46, in main
    cur.execute("""INSERT INTO feeddata_iii(III_UnixTimesstamp, III_Timestamp, III_Source, III_Title, III_Text, III_Link, III_Epic, III_CommentNr, III_Author) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)""",item)
  File "C:\Python27\lib\site-packages\MySQLdb\cursors.py", line 187, in execute
    query = query % tuple([db.literal(item) for item in args])
  File "C:\Python27\lib\site-packages\MySQLdb\connections.py", line 278, in literal
    return self.escape(o, self.encoders)
  File "C:\Python27\lib\site-packages\MySQLdb\connections.py", line 208, in unicode_literal
    return db.literal(u.encode(unicode_literal.charset))
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u201c' in position 34: ordinal not in range(256)
Zum deinem DB Hinweis:

Da hast du vlt voll ins schwarze getroffen. Ich weiss nicht wie die aktuelle DB formatiert ist (Könnte gut sein, dass ich aktuell einfach Server Default eingestellt habe), ich kann aber eine neue DB erstellen. Dabei könnte ich folgendes auswählen: utf8 - default collation, utf8 - utf8_bin usw.
> Meintest du das?
> Und wenn ja welche Einstellung würdest du da nutzen, da es mehr als eine utf8 Option gibt?

Zu der Aufteilung der Tabellen:

Es ist Teil der Anforderung, dass die Daten in der verschiedenen HPs in verschiedenen Tabellen liegen. Den Präfix habe ich mit in den Spaltennamen genommen, dass wenn ich die Tabellen später in SQL joine, ich die Spalten dennoch eindeutig am Spaltenname identifizieren kann und nicht der Tabellennamen immer mitgeführt werden muss.
> Würdest du hier etwas anderes raten?
BlackJack

@h0rnung: Ich bin da kein MySQL-Experte, sorry. Und bei den MySQL-Datenbanken an die ich bisher ran musste und die Text enthalten haben, bin ich immer mit `SQLAlchemy` dran gegangen und da hat ein an die Verbindungszeichenkette angehängtes '?charset=utf8' ausgereicht das Unicode keine Probleme machte.

Wenn das mit den verschiedenen Tabellen Teil der Anforderung ist, dann stelle ich wohl die Anforderung in Frage. Wer hat die aufgestellt, und warum so?

Man kann den Tabellen beim Abfragen ja einen Alias verpassen, also zum Beispiel zum Präfix verkürzen. Dann muss man statt `LSE_Title` das gleich lange `LSE.Title` verwenden wenn man die beiden Tabellen JOINed.
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Die Anforderung kommt vom Chef. Deine Argumente ergeben Sinn - werde das mit ihm besprechen.

Siehst du denn die Möglichkeit den Code in der Art abzuändern, dass er bei so einem Fehler einfach in 4 Minuten erneut versucht den nächsten Feed herunterzuladen und damit den im falschen Format vorliegenden Feed ignoriert?
BlackJack

@h0rnung: Was heisst „im falschen Format”? Da enthält halt irgend einer der Textwerte ein Zeichen was nicht als Latin-1 kodiert werden kann. Damit sollte ein Programm heutzutage eigentlich umgehen können statt zu sagen das sei ”falsch”. Mit anderen Worten: Latin-1 ist keine Kodierung die man für im Grunde beliebige Textdaten aus dem Internet verwenden kann. Da solltest Du ansetzen. Ansonsten entgehen Dir systematisch Beiträge in den denen so etwas wie typographische Anführungszeichen („”), oder echte Bindestriche (—) enthalten sind, oder von Benutzern mit Namen die Zeichen enthalten, welche nicht in Latin-1 enthalten sind.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@h0rnung: Wer heutzutage für Text noch etwas anderes als irgendeine Unicode-Variante, wird entweder dazu gezwungen, oder hat das Thema Encoding noch nicht verstanden. Die Verschiedenen utf8_xxx Varianten in MySQL betreffen die Vergleichsoperationen von Strings, da gibt es eben für jede Sprache eigene Regeln (also z.B. dass ä wie a behandelt wird, oder ä gleich nach a einsortiert wird, oder ...)
Wie bei jeder Variablenbenennung, sollten auch Tabellennamen nicht zum Speichern von Inhalt mißbraucht werden. Die URL ist eindeutig eine Tabellenspalte und kein Tabellenname. Der Aufwand für das Hinzufügen einer weiteren URL ist im einen Fall enorm, im anderen Fall quasi null.
Warum verwendest Du für Zeit/Datumsangaben einen Integer bzw. einen String? Dafür gibt es in Datenbanken spezielle Typen, am besten inklusive Zeitzone oder Du garantierst, dass nur UTC-Zeiten geschrieben werden. Ansonsten ist es sehr schwierig, zum Beispiel nach Tagen zu gruppieren. Heutige Datenbanksysteme bieten kaum einen Vorteil von VARCHAR gegenüber TEXT. Der Nachteil ist, dass falls die Zeichenanzahl doch nicht ausreicht, es zu Fehlern kommt, die speziell Abzufangen sind. Was soll dann passieren? Abschneiden, Wegschmeißen, komplett Aussteigen. Das mußt Du jetzt planen, einprogrammieren und das Verhalten entsprechend testen.
Es gibt `execute_many`.
BlackJack

@h0rnung: Habe einen Programmfehler entdeckt: In Zeile 28 das sollte wohl eher ein Tupel in der Liste sein und keine Menge, denn bei einer Menge ist die Reihenfolge der Elemente nicht garantiert, das beschreibt also entweder den Header 'User-agent: Mozilla/5.0' oder 'Mozilla/5.0: User-agent', und letzeres ist falsch. Allerdings wird der Wert anscheinend sowieso nirgends verwendet. Genau wie einige Importe. Von den 8 Importen werden letztendlich nur drei tatsächlich benötigt.

Ich sehe gerade dass Du in den Tabellen sogar schon redundant die Quelle des Datensatzes speicherst. Das macht zwei verschiedene Tabellen für die Quellen ja noch unsinniger. Oder halt dieses Feld überflüssig, denn da steht dann ja in jedem Datensatz grundsätzlich der selbe Wert drin.

Den Zeitpunkt an dem der Datensatz erzeugt wurde, würde ich auch wie die ID automatisch von der Datenbank generieren lassen. Es sei denn der Zeitunterschied zwischen parsen des Datensatzes und tatsächlichem Eintragen in die Datenbank spielt tatsächlich eine Rolle. Benötigst Du diese Information überhaupt?

Die ``PRIMARY KEY``-Einschränkung impliziert ``NOT NULL`` eigentlich schon, denn ein Primärschlüssel muss ja eindeutig sein. Das SQL kann man lesbarer formatieren. Und ``PRIMARY KEY`` würde ich entweder direkt beim Feld angeben oder aber erst ganz zum Schluss. Ich weiss gar nicht ob der SQL-Standard das Mischen von Spaltendeklarationen und Tabellen-Constraints überhaupt erlaubt.

Wenn man alle Feed-Einträge in *einer* Tabelle speichert, dann würde ich die möglichen Quellen in eine eigene Tabelle auslagern und nur eine ID als Fremdschlüssel in der Eintragstabelle speichern. Dann sind Anfragen darauf effizienter und man kann zum Beispiel nicht nur das Kürzel, sondern auch die komplette URL von dem jeweiligen Feed in der Datenbank hinterlegen.

Ich sehe übrigens gerade nicht ob/wo Du verhinderst das Feed-Einträge mehrfach gespeichert werden‽

Die beiden `feed_load_*()`-Funktionen unterscheiden sich ja nur geringfügig. Da würde ich eher den Unterschied heraus ziehen, also eine Funktion um die beiden Informationen aus einem Eintrag zu extrahieren pro Feed schreiben und die dann als Argument übergeben. Desweiteren würde ich das Parsen *eines* Eintrags in eine eigene Funktion auslagern, und die Funktion zum Parsen eines Feeds etwas robuster machen. Denn momentan bricht das ja ab sobald in *einem* Eintrag ein Problem auftritt. Es bricht sogar das gesamte Programm ab. An der Stelle würde man wahrscheinlich eher das Problem protokollieren und danach mit dem nächsten Eintrag weiter machen.

Das Parsen der Informationen aus den Links mittels `split()` ist nicht robust. Da sollte man die URL tatsächlich nach den Regeln von URLs parsen. Du verlässt Dich zum Beispiel auf die Reihenfolge der Query-Parameter statt auf die Namen. Zum Parsen von URLs und Querys gibt es in der Python-Standardbibliothek Funktionen.

In der `main()`-Funktion schreibst Du das dort der Zeitstempel des jeweils ersten Eintrags ausgegeben wird, was aber nicht stimmt, denn an Index 1 steht der *zweite* Eintrag. Das Programm bekommt an der Stelle auch ein Problem wenn der Feed *gar keine* Einträge enthalten hat, denn dann gibt es dort einen `IndexError`.

Das in der Funktion die Arbeitsschritte für zwei verschiedene Feeds jeweils ”gruppiert” sind, macht es umständlich neue Feeds hinzuzufügen oder auszunehmen. Besser wäre es alle Arbeitsschritte für einen Feed nacheinander zu erledigen und dann erst den nächsten anzugehen. Dann kann man die Verarbeitung *eines* Feeds auch in eine Funktion auslagern und die dann für jeden Feed aufrufen.

Das die Feeds sequentiell abgearbeitet werden, wird problematisch wenn es mit einem Feed Netzwerkprobleme gibt, also wenn sich der Server ewig Zeit lässt mit der Antwort. Das blockiert dann auch den anderen Feed unnötig. Ausserdem könnte man hier wieder Programmabbrüche verhindern wollen, wenn einer der beiden Feeds Probleme bereitet.

Eventuell macht es auch Sinn das herunterladen der Feeds und die Verarbeitung zu trennen. Ich würde wahrscheinlich erst einmal nur etwas schreiben um die Feeds regelmässig abzufragen und 1:1 zu speichern. Vielleicht zusammen mit den Header-Daten von der Serverantwort und dem Zeitpunkt der Abfrage und den relevanten Abfragedaten. Also sozusagen wirklich keine Daten wegwerfen.

Dann kann man unabhängig von der weiteren Verarbeitung erst einmal die Daten sammeln und der komplette Vorgang ist später nachvollziehbar.

Als nächsten Schritt kann man dann Code schreiben der die Feeds in eine Datenbank importiert. Gerade in der Entwicklungsphase geht das dann auch schneller auszuprobieren lokale, bereits heruntergeladene Feeds zu importieren, als jedes mal für einen Testlauf die Feeds von den Servern abzufragen — mit der entsprechenden Wartezeit zwischen den Abfragen. Es lassen sich dann auch einfacher künstliche Feeds für Testfälle erstellen.
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

@Sirius

Danke für deine Antwort.

- Also sagst du, ich soll die DB als unicode Variante deklarieren und entgehe somit weiteren Problemen mit dem Format der Feeds?

- Tabellennamen sowie Spalten Aufteilung muss ich wie in der Anforderung besprochen abliefern. Werde aber deine und Blackjacks Bedenken vorbringen.

- Als eindeutigen Timestamp benutzte ich den Unix-Timestamp. Der vom Feedprovider bereitgestellte Timestamp passt leider in kein Datumsformat das von MySQL unterstützt wird. Hab da sämtliche Formate durchprobiert und bekomme immer Fehlermeldungen zurück. (So sieht ein Timestamp aus: 'Thu, 03 Jul 2014 12:02:09 GMT' ... weisst du vllt welches Format ich da bei der Speicherung benutzen sollte?)

Zum letzten Punkt:

Ich würde natürlich gerne so wenig wie möglich weglassen. Zur Not aber den gesamten feed und mit dem nächsten weitermachen. Das Vorgehen würde ich anhand einer Stichprobe ausprobieren und schauen wieviele Feeds mir täglich dadurch fehlen und ob das verträglich ist. Besser wäre es aber wohl schon wenn einfach nur der eine Feed oder gar nur das eine Zeichen einfach nicht in der DB auftauchen würden.

Gruesse
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

@ BlackJack

... auch dir herzlichen Dank für die Antwort!

- Habe unsinnige LoC und Importe auskommentiert. Danke!

- Ueber Tabellenspalten, deren Sinn sowie die Namensgebung muss ich nochmal mit dem Anforderungssteller in Kontakt treten. Kann ich so nicht ändern - die Anforderung ist dahingehend etwas schwammig formuliert!

- Den Zeitpunkt Speicher deswegen ab, da ich bisher keine Möglichkeit gefunden habe, den vom Feed bereit gestellten Timestamp auch als solchen abzuspeichern (Siehe Antwort an Sirius)!

- Primary Key hab ich nach hinten gestellt ... hat aber bisher eigentlich immer geklappt. Dennoch Danke!

- Dubletten gibt es - sollen aber auf MySQL Ebene behandelt werden und nicht im Python-SQL-Code oder kennst du einen geschickten SQL-Trick den ich hier noch einbauen könnte um das abspeichern von Dubletten relativ simpel zu verhindern? Die Kombination aus Kommentar Nummer, Author und Source sollte Kommentare eindeutig identifizieren!

- Das mit der Split Funktion ist mir bewusst ... hatte zu dem Thema, glaube ich, sogar schonmal einen Thema hier eröffnet. Leider stelle ich mich aktuell zu dumm an den feedparser zu verwenden. Hast du mir da ein Code Beispiel?

Deinen abschliessenden Punkt mit dem separaten Abspeichern der feeds finde ich sehr gut. Auch das werde ich ins Anfordeurngsgespraech mitnehmen!

Ganz herzlichen Dank für die toll Hilfe. Ein Student mit viel zu wenig praktischer Programmiererfahrung is zu tiefstem Dank verpflichtet 8)
BlackJack

@h0rnung: Solche Feeds sind XML und XML enthält Unicode, also sollte man das auch so speichern das alle Unicode-Zeichen gespeichert werden können. UTF-8 bietet sich da als Kodierung an. Wie gesagt habe ich das immer über SQLAlchemy benutzt, aber ich weiss, dass es für die Zeichenkodierung ein Argument beim `connect()` geben muss. Ich vermute mal ganz stark dass es `charset` heisst.

Das Datum von Feed-Einträgen entspricht den Datumsangaben wie sie in E-Mail-Headern spezifiziert sind und `feedparser` hält das auch schon als `time.struct_time` vor (als GMT-Zeit). Das musst Du dann nur noch in ein passendes Format für die Datenbank bringen, damit es als Wert für eine DATETIME-Spalte verwendbar ist. DB-API V2 Module haben dafür einen `Timestamp`-Typ den man verwenden kann. Du willst solche Daten nicht als Zeichenketten an die Datenbank übergeben, denn welches Format die DB als Zeichenkette versteht, kann unter anderem von den Einstellungen des DB-Servers abhängen.

Auf SQL-Seite kann man Doubletten durch entsprechende UNIQUE-Constraints verhindern. Und dann im Client-Code entweder einfach einfügen und auf die Ausnahme entsprechend reagieren wenn man versucht etwas einzufügen was den Constraint verletzt, oder wenn man auch nicht-standard-SQL verwenden möchte, kennt MySQL bei INSERT und UPDATE den Zusatz IGNORE bei dem solche Versuche einfach ignoriert werden. Kommentar-Nummer und Source sollte eigentlich reichen.

Das Parsen der Daten aus dem Link hat nichts mehr mit `feedparser` zu tun. Von da bekommst Du nur den Link selber. Den in seine Bestandteile zu zerlegen um an den Query-Anteil zu kommen, und den dann zu parsen um an die Schlüssel und Werte zu kommen ist Aufgabe der Funktionen aus dem `urlparse`-Modul aus der Standardbibliothek. Ungetestet für die 'iii'-Quelle:

Code: Alles auswählen

from urlparse import parse_qs, urlsplit

III_LINK_EPIC_PREFIX = 'cotn:'


def parse_iii_link(link):
    query = parse_qs(urlsplit(link).query)
    epic = query['code'][0]
    if not epic.startswith(III_LINK_EPIC_PREFIX):
        raise ValueError(
            'epic does not start with {0!r}'.format(III_LINK_EPIC_PREFIX)
        )
    return (epic[len(III_LINK_EPIC_PREFIX):], int(query['id'][0]))


def process_iii_entry(entry):
    epic, comment_id = parse_iii_link(entry.link)
    return [
        MySQLdb.Timestamp(*entry.published_parsed[:6]),
        'iii',
        entry.title,
        entry.summary,
        entry.link,
        epic,
        comment_id,
        entry.author
    ]
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Servus BlackJack,

einmal mehr herzlichen Dank für die tolle Unterstützung. Habe so eben versucht eine DB, welche utf8 - default collection als Format hat, mit meinen Feeds zu befuellen: Selber Fehler.

Zum Unicode Fehler:

Verstehe ich dich richtig, dass du der Meinung bist, dass bei meinem connect() Argument etwas fehlt damit die Daten richtig ausgelesen werden?

Zum Url-parse Teil:

Ich weiss, dass meine Frage etwas frech ist, aber könntest du das Statement vervollständigen (ohne SQL Teil nur mit Print Ausgabe des Feeds)? Ich baue da jetzt ne Stunde rum und verstehe irgendwie nicht sonderlich viel :(

Herzlichen Dank und Grüße
BlackJack

@h0rnung: Du musst der MySQL-Verbindung beim erstellen sagen das UTF-8 statt ISO-8859-1 als Kodierung verwendet werden soll.

Die `process_iii_entry()`-Funktion verarbeitet *einen* Eintrag des Feeds zu einer Liste mit den Werten für die Datenbank. Du musst die halt nur für alle Einträge aus dem Feed aufrufen.

Die beiden Funktionen mal an einem Beispielwert ausprobiert:

Code: Alles auswählen

In [57]: link
Out[57]: u'http://www.iii.co.uk/investment/detail?code=cotn:WTI.L&id=11283542&display=discussion&action=detail'

In [58]: parse_iii_link(link)
Out[58]: (u'WTI.L', 11283542)

In [59]: process_iii_entry(entry)
Out[59]: 
[datetime.datetime(2014, 7, 7, 10, 12, 16),
 'iii',
 u'Re: July then...mining starts..quarterly...  ( WTI.L)',
 u'ah yes...the quarterly.....sweet joy or deep sorrow. We shall know soon. <br />\n By hanser',
 u'http://www.iii.co.uk/investment/detail?code=cotn:WTI.L&id=11283542&display=discussion&action=detail',
 u'WTI.L',
 11283542,
 u'hanser']

In [60]: [process_iii_entry(e) for e in feed.entries]
# Eine Liste mit einer Liste pro Eintrag aus `feed.entries`
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Servus,

ich komm leider immer noch nicht mit. Warum verwendest du III_LINK_EPIC_PREFIX = 'cotn:' wobei mein Feedlink auch etwas anders aussieht als deiner:

mein Link http://www.iii.co.uk/site_wide_discussi ... e_rss2.epl

dein Link 'http://www.iii.co.uk/investment/detail? ... ion=detail'

Dem entsprechend funktioniert bei diesem Code auch nicht das einlesen des Feeds:

Code: Alles auswählen

from urlparse import parse_qs, urlsplit
import MySQLdb
import time
 
III_LINK_EPIC_PREFIX = 'cotn:'

def parse_iii_link(link):
    query = parse_qs(urlsplit(link).query)
    epic = query['code'][0]
    if not epic.startswith(III_LINK_EPIC_PREFIX):
        raise ValueError(
            'epic does not start with {0!r}'.format(III_LINK_EPIC_PREFIX)
        )
    return (epic[len(III_LINK_EPIC_PREFIX):], int(query['id'][0]))

def process_iii_entry(entry):
    epic, comment_id = parse_iii_link(entry.link)
    return [
        MySQLdb.Timestamp(*entry.published_parsed[:6]),
        'iii',
        entry.title,
        entry.summary,
        entry.link,
        epic,
        comment_id,
        entry.author
    ]

def main():
    print process_iii_entry(entry)
Kannst du mir da nochmal weiterhelfen :( ?

Gruesse
h0rnung
User
Beiträge: 46
Registriert: Mittwoch 28. Mai 2014, 11:41

Hier fuer alle mit dem selben Anfangsproblem die Lösung:

Erhaltet ihr diesen Error: UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026' in position 32: ordinal not in range(256) in Zusammenhang mit einer MySQL DB koennt ihr es mit folgendem SQL Statement versuchen. Hat bei mir geklappt :lol:

Code: Alles auswählen

.....
db = MySQLdb.connect(host="localhost", 
                     user="root", 
                     passwd="***", 
                     db="sentimentanalysis_unicode",
                     charset="utf8") 

cur = db.cursor()

cur.execute("SET NAMES utf8")
cur.execute("SET CHARACTER SET utf8")
cur.execute("SET character_set_connection=utf8")
......
BlackJack

@h0rnung: Die Konstante definiere ich weil der wert mehrfach benutzt wird, und man ihn so nur einmal tatsächlich schreiben muss, und somit das Risiko minimiert das man sich verschreibt.

Unsere Links *für* den Feed sehen nicht anders aus, und die Links *in* dem Feed in jedem einzelnen Eintrag sicher auch nicht. Du zerlegst diesen Link ja auch an Zeichenketten die im Feed-Link gar nicht vorhanden sind. Der ist an der Stelle ja auch irrelevant.
Antworten