Re-Pricing Ebay mit API und EAN Code

Du hast eine Idee für ein Projekt?
Antworten
Tec-World
User
Beiträge: 4
Registriert: Dienstag 14. August 2018, 20:15

Dienstag 14. August 2018, 20:29

Hallo zusammen,

ich bin vollkommener Neuling in Python und versuche mich an einem kleinen Projekt und steck leider fest. Vielleicht könnte mir jemand helfen?

Folgendes Ziel:

Ich habe eine TXT Datei, wo ich mehere EAN Codes aufgeführt habe. Diese sind pro Zeile ein EAN Code. Mit Hilfe von der eBay API soll über ein Script dann die Datei ausgelesen werden, über das Script und die API die Daten bei Ebay ausgelesen (Titel, Preis, Zustand) werden und anschließend alles als eine CSV Datei gespeichert werden.

Aktueller Status

2 Dateien
  • searches.txt
  • ebayapi.py

searches.txt

Code: Alles auswählen

4015704268300
4015704268287
008562008168
008562016835

ebayapi.py

Code: Alles auswählen

key = 'HierKommtDeineEbayAPIrein'
import json
import requests
from lxml import html
import urllib3
import requests
import unicodecsv as csv
from traceback import format_exc
import csv
search_term = []
with open("searches.txt", 'r') as searchfile:
	searches = searchfile.readlines()
	print(searches)
for item1 in searches:
        url = ('http://svcs.ebay.com/services/search/FindingService/v1\
?OPERATION-NAME=findItemsByKeywords\
&sortOrder=PricePlusShippingLowest\
&GLOBAL-ID=EBAY-DE&buyerPostalCode=22113&SERVICE-VERSION=1.13.0\
&SECURITY-APPNAME=' + key +
'&RESPONSE-DATA-FORMAT=JSON\
&REST-PAYLOAD\
&itemFilter(0).name=Condition\
&itemFilter(0).value=New\
&itemFilter(1).name=MaxPrice\
&itemFilter(1).value=100000.0\
&itemFilter(1).paramName=Currency\
&itemFilter(1).paramValue=EUR\
&keywords=' + item1)

        apiResult = requests.get(url)
        parseddoc = apiResult.json()

        
        for item in (parseddoc["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"]):
                title = item["title"][0]
                condition = item['condition'][0]['conditionDisplayName'][0]
                price = item['sellingStatus'][0]['convertedCurrentPrice'][0]['__value__']
                ean = 'item1'
#                print(title + " " + price + " " + condition + " " + ean)
                            


print ("Writing scraped data to ebay-scraped-data.csv")
                                      
with open('Repricing.csv', 'a') as myFile: 
        myFields = ["'title'","'condition'","'price'", "'ean'"]
        writer = csv.DictWriter(myFile, fieldnames=myFields, delimiter=';', lineterminator='\n', quoting=csv.QUOTE_ALL)
        writer.writeheader()

        extract = []
        for i in range(1):
                for item in (parseddoc["findItemsByKeywordsResponse"][0]["searchResult"][0]["item"]):
                        title = item["title"][0]
                        condition = item['condition'][0]['conditionDisplayName'][0]
                        price = item['sellingStatus'][0]['convertedCurrentPrice'][0]['__value__']
                        ean = item1
                        data = {
                                "'title'": "'"+title+"'",
                                "'condition'": "'"+condition+"'",
                                "'price'": "'"+price+"'",
                                "'ean'": "'"+ean+"'"
                        }
                        extract.append(data)

                        writer.writerow(data)

               
#                writer.writerow({"'title'": "'" + title + "'", "'condition'": "'" + condition + "'", "'price'": "'" + price + "'", "'ean'": "'" + ean  + "'"})


Problem:
Leider bekomme ich immer nur zum letzten Wert die ausgelesenen Daten angezeigt (egal ob open xxx "a" oder open xxx "w"). Ich bekomme es leider nicht hin, dass er mir die anderen EAN Nummern mit Daten auch in die Liste schreibt.
Hat hierzu vielleicht jemand eine Lösung?

Habt vielen Dank vorab
Benutzeravatar
__blackjack__
User
Beiträge: 1450
Registriert: Samstag 2. Juni 2018, 10:21

Dienstag 14. August 2018, 22:21

@Tec-World: Ich würde sagen Du solltest das noch mal überarbeiten und alles unbenutzte rauswerfen. Das `json`-Modul wird importiert, aber nicht verwendet. `requests` wird zweimal importiert. `html` aus `lxml` wird importiert und nicht verwendet. Genau wie `urllib3` und `format_exc` aus dem `traceback`-Modul. Und `unicodecsv` wird auch nicht verwendet, weil das als `csv` importiert, aber wenig später durch ``import csv`` verdeckt wird.

`search_term` wird definiert aber nicht verwendet. `extract` wird definiert und es werden Daten in die Liste geschrieben, dann aber auch nicht verwendet.

Einige Namen könnten besser gewählt sein. Was soll die 1 bei `item1`? Nummern an Namen hängen ist ein Warnzeichen das was falsch läuft. `item` ist auch verdammt generisch. Der Name soll dem Leser vermitteln was der Wert dahinter im Programm bedeutet. Hier handelt es sich um ein Wort das bei der Suche als Schlüsselwort dient, beziehungsweise noch konkreter um eine EAN. Das kann ich an `item1` nicht ablesen.

Die URL mit den \ auf mehrere Zeilen zu verteilen ist fehleranfällig, weil nach dem \ kein Leerzeichen stehen darf und solche Fehler blöd zu suchen/finden sind. Ausserdem zerstört es die Einrückung, die zum lesen wichtig ist.

Eingerückt wird vier Leerzeichen pro Ebene, nicht acht.

`apiResult` hält sich nicht an die Namenskonventionen. klein_mit_unterstrichen für alles ausser Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Zudem ist der Name nicht richtig, denn das ist nur die HTTP-Antwort auf die Anfrage, das Ergebnis der API steht im JSON das dort zurückgegeben wird.

Die erste Schleife über das API-Ergebnis macht keinen Sinn weil in der Schleife nicht wirklich etwas mit den Daten gemacht wird. Die kann also komplett entfallen.

Und dann wären wir auch schon beim Problem: Du machst in der Schleife nichts mit den ganzen abgefragten Ergebnissen. Nur *nach* der Schleife etwas mit dem *letzten* Ergebnis. Weshalb halt auch nur das letzte Ergebnis weiterverarbeitet wird.

Die Aussage der `print()`-Ausgabe vor dem Öffnen der CSV-Datei stimmt nicht mit dem folgenden Code überein. Wenn ein Dateiname mehr als einmal benutzt wird, sollte er trotzdem nur einmal im Quelltext stehen, damit genau so etwas nicht passiert.

Der Präfix `my` bei Namen macht in 99,99999% der Fälle keinen Sinn. Das ist einfach nur ein überflüssiges Anhängsel ohne Informationswert.

Bei den Feldern und Werten für die CSV-Datei sind eindeutig zu viele Anführungsstriche involviert.

Die CSV-Datei wird zum Anhängen von Zeilen geöffnet, und dann wird die Kopfzeile mit den Spaltennamen geschrieben, was keinen Sinn macht wenn in der Datei schon Daten stehen.

Eine ``for``-Schleife die grundsätzlich nur einmal durchlaufen wird, ist absolut sinnfrei. Wie kommt so etwas zustande?

Bei solchen verketteten Wörterbuch/Listen-Zugriffen verwende ich gerne das externe Modul `addict`.

Ich lande dann ungefähr hier, wobei das immer noch den Fehler enthält, weil ich ja nicht weiss wie genau Du den beheben möchtest, also welches Verhalten da am Ende herauskommen soll. Ungetestet:

Code: Alles auswählen

import csv

from addict import Dict
import requests

KEY = 'HierKommtDeineEbayAPIrein'


def main():
    with open('searches.txt', 'r') as ean_file:
        eans = ean_file.readlines()
        print(eans)
    
    for ean in eans:
        # 
        # TODO Cleaner solution would be to pass the parameters as
        #   dictionary to `requests.get()` instead of building the
        #   URL manually.
        # 
        url = (
            'http://svcs.ebay.com/services/search/FindingService/v1'
            '?OPERATION-NAME=findItemsByKeywords'
            '&sortOrder=PricePlusShippingLowest'
            '&GLOBAL-ID=EBAY-DE&buyerPostalCode=22113&SERVICE-VERSION=1.13.0'
            '&SECURITY-APPNAME=' + KEY +
            '&RESPONSE-DATA-FORMAT=JSON'
            '&REST-PAYLOAD'
            '&itemFilter(0).name=Condition'
            '&itemFilter(0).value=New'
            '&itemFilter(1).name=MaxPrice'
            '&itemFilter(1).value=100000.0'
            '&itemFilter(1).paramName=Currency'
            '&itemFilter(1).paramValue=EUR'
            '&keywords=' + ean
        )
        api_result = Dict(requests.get(url).json())
    
    filename = 'Repricing.csv'
    print('Writing scraped data to', filename)
    with open(filename, 'a') as csv_file: 
        writer = csv.DictWriter(
            csv_file,
            fieldnames=['title', 'condition', 'price', 'ean'],
            delimiter=';',
            lineterminator='\n',
            quoting=csv.QUOTE_ALL,
        )
        writer.writeheader()

        for item in (
            api_result.findItemsByKeywordsResponse[0].searchResult[0].item
        ):
            title = item.title[0]
            condition = item.condition[0].conditionDisplayName[0]
            price = item.sellingStatus[0].convertedCurrentPrice[0].__value__
            writer.writerow(
                {
                    'title': title,
                    'condition': condition,
                    'price': price,
                    # 
                    # FIXME Last `ean` from previous loop!  Possibly
                    #   undefined if file is empty!
                    # 
                    'ean': ean,  
                }
            )


if __name__ == '__main__':
    main()
Das ist auch schon recht lang für *eine* Funktion und macht zwei gut trennbare Dinge: Daten einlesen und Daten schreiben. Eventuell kann man das Umwandeln des einen Wörterbuchs in das andere auch als einzelne Funktion heraus ziehen.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Tec-World
User
Beiträge: 4
Registriert: Dienstag 14. August 2018, 20:15

Dienstag 28. August 2018, 21:43

Hi __blackjack__,

vielen Dank für deine mehr als Ausführliche Erklärung. Danke dafür!!!

Das ist quasi mein erster Code, den ich überhaupt mal probiert habe zu schreiben und aus mehreren Anleitungen, Videos und verschiedenen Codes versucht einen zu machen.
Danke für das aufräumen des Codes. Ich werde mir die Tage das genauer anschauen und prüfen, wie ich den Fehler vielleicht gelöst bekomme.

Das Modul habe ich nun installiert bekommen und den Code angepasst bzw. ausprobiert! Es funktioniert genau so wie ich es mir vorgestellt habe!
Außer das die "Headline" doppelt auftaucht, was aber nur eine Schönheitskorrektur ist, funktioniert es einwandfrei.

Habe besten Dank für deine Hilfe!!! :)
Benutzeravatar
__blackjack__
User
Beiträge: 1450
Registriert: Samstag 2. Juni 2018, 10:21

Mittwoch 29. August 2018, 09:14

@Tec-World: Die Kopszeile wird merhrfach geschrieben, weil Du das ja für jede EAN erneut machst. Statt die Datei für jede EAN im „append“-Modus zu öffnen, würde es mehr Sinn machen die einmal am Anfang zum schreiben zu öffnen und zwischen den EANs nicht wieder zu schliessen. Dann kann man auch *einmal* am Anfang die Kopfzeile schreiben.

Was sich dadurch ändert ist natürlich das eine eventuell vorhandene Datei dadurch überschrieben wird.

Ungetestet:

Code: Alles auswählen

import csv

from addict import Dict
import requests

KEY = 'HierKommtDeineEbayAPIrein'


def get_items(ean):
    # 
    # TODO Cleaner solution would be to pass the parameters as
    #   dictionary to `requests.get()` instead of building the
    #   URL manually.
    # 
    url = (
        'http://svcs.ebay.com/services/search/FindingService/v1'
        '?OPERATION-NAME=findItemsByKeywords'
        '&sortOrder=PricePlusShippingLowest'
        '&GLOBAL-ID=EBAY-DE&buyerPostalCode=22113&SERVICE-VERSION=1.13.0'
        '&SECURITY-APPNAME=' + KEY +
        '&RESPONSE-DATA-FORMAT=JSON'
        '&REST-PAYLOAD'
        '&itemFilter(0).name=Condition'
        '&itemFilter(0).value=New'
        '&itemFilter(1).name=MaxPrice'
        '&itemFilter(1).value=100000.0'
        '&itemFilter(1).paramName=Currency'
        '&itemFilter(1).paramValue=EUR'
        '&keywords=' + ean
    )
    api_result = Dict(requests.get(url).json())
    for item in api_result.findItemsByKeywordsResponse[0].searchResult[0].item:
        yield {
            'title': item.title[0],
            'condition': item.condition[0].conditionDisplayName[0],
            'price': item.sellingStatus[0].convertedCurrentPrice[0].__value__,
            'ean': ean,  
        }


def main():
    with open('searches.txt', 'r') as ean_file:
        filename = 'Repricing.csv'
        print('Writing scraped data to', filename)
        with open(filename, 'w') as csv_file: 
            writer = csv.DictWriter(
                csv_file,
                fieldnames=['title', 'condition', 'price', 'ean'],
                delimiter=';',
                lineterminator='\n',
                quoting=csv.QUOTE_ALL,
            )
            writer.writeheader()
            for ean_line in ean_file:
                writer.writerows(get_items(ean_line.strip()))


if __name__ == '__main__':
    main()

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Benutzeravatar
kbr
User
Beiträge: 949
Registriert: Mittwoch 15. Oktober 2008, 09:27

Mittwoch 29. August 2018, 09:54

Was ich in ganz angenehm finde, ist die Möglichkeit, in einem Kontext mehr als eine Datei öffnen zu können. Was im konkreten Fall eine Einrückebene sparen würde – auch wenn das hauptsächlich Kosmetik ist.

Code: Alles auswählen

    filename = 'Repricing.csv'
    with open('searches.txt', 'r') as ean_file, open(filename, 'w') as csv_file:
        print('Writing scraped data to', filename)
        ... 
Tec-World
User
Beiträge: 4
Registriert: Dienstag 14. August 2018, 20:15

Donnerstag 30. August 2018, 20:13

Hat jemand noch eine Idee, wie ich einen Loop rein bekomme, sodass in der Datei mehrere EAN Nummer (Pro Zeile eine ist) und diese via Loop abgefragt wird und in die CSV Datei geschrieben wird?
Da komm ich leider aktuell nicht weiter :(
Benutzeravatar
__blackjack__
User
Beiträge: 1450
Registriert: Samstag 2. Juni 2018, 10:21

Donnerstag 30. August 2018, 22:41

@Tec-World: Das macht mein Code doch‽ Da ist eine Schleife über die Zeilen in der Datei.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Tec-World
User
Beiträge: 4
Registriert: Dienstag 14. August 2018, 20:15

Freitag 31. August 2018, 17:55

Passt :!:

Sorry mein Fehler... funktioniert alles. Habt vielen DANK für die HILFE!
Antworten