Heim > Artikel > Backend-Entwicklung > Zeit zu gehen? Zeit zum Wiederaufbau! Twitter machen
Die wichtigsten Funktionen eines neuen sozialen Netzwerks für Benutzer, die Musk und Twitter satt haben, sind wie folgt:
Weniger wichtige, aber auf jeden Fall hilfreiche Funktionen der Plattform;
In diesem Beitrag konzentrieren wir uns auf die erste Funktion. Importieren der archive.zip-Datei von Twitter.
Twitter macht es nicht ganz einfach, an Ihre Daten zu kommen. Es ist großartig, dass sie Ihnen Zugriff darauf gewähren (gesetzlich gesehen müssen sie das). Das Format ist Mist.
Es handelt sich eigentlich um ein Mini-Webarchiv und alle Ihre Daten stecken in JavaScript-Dateien. Es handelt sich eher um eine Web-App als um eine praktische Datenspeicherung.
Wenn Sie die Datei „Ihr Archiv.html“ öffnen, erhalten Sie etwa Folgendes:
Hinweis: Ich habe ziemlich früh die Entscheidung getroffen, Next.js für die Website, Go und GraphQL für das Backend zu verwenden.
Was tun Sie also, wenn es sich bei Ihren Daten nicht um strukturierte Daten handelt?
Nun, Sie analysieren es.
Schauen Sie sich die offiziellen Dokumente zu den ersten Schritten mit Go an und richten Sie Ihr Projektverzeichnis ein.
Wir werden diesen Prozess gemeinsam meistern. Es scheint eine der wichtigsten Funktionen zu sein, um Leute anzulocken, die sich zu sehr mit TwitterX verbunden fühlen.
Der erste Schritt besteht darin, eine main.go-Datei zu erstellen. In dieser Datei werden wir (hah) ein paar Sachen machen;
package main import ( "fmt" "os" ) func run(path string) { fmt.Println("Path:", path) } func main() { if len(os.Args) < 2 { fmt.Println("Please provide a path as an argument.") return } path := os.Args[1] run(path) }
Bei jedem Schritt führen wir die Datei wie folgt aus:
go run main.go twitter.zip
Wenn Sie keinen Twitter-Archivexport haben, erstellen Sie eine einfache manifest.js-Datei und geben Sie ihr das folgende JavaScript.
window.__THAR_CONFIG = { "userInfo" : { "accountId" : "1234567890", "userName" : "lukeocodes", "displayName" : "Luke ✨" }, };
Komprimieren Sie das in Ihre twitter.zip-Datei, die wir durchgehend verwenden werden.
Der nächste Schritt besteht darin, den Inhalt der ZIP-Datei zu lesen. Wir möchten dies so effizient wie möglich tun und die Zeit zum Extrahieren der Daten auf der Festplatte verkürzen.
Es gibt viele Dateien in der ZIP-Datei, die auch nicht extrahiert werden müssen.
Wir bearbeiten die Datei main.go;
package main import ( "archive/zip" "fmt" "log" "os" ) func run(path string) { // Open the zip file r, err := zip.OpenReader(path) if err != nil { log.Fatal(err) } defer r.Close() // Iterate through the files in the zip archive fmt.Println("Files in the zip archive:") for _, f := range r.File { fmt.Println(f.Name) } } func main() { // Example usage if len(os.Args) < 2 { log.Fatal("Please provide the path to the zip file as an argument.") } path:= os.Args[1] run(path) }
Diese Archivdatei ist wirklich nicht hilfreich. Wir möchten nur nach .js-Dateien suchen, und zwar nur im Verzeichnis /data.
package main import ( "archive/zip" "fmt" "io/ioutil" "log" "os" "path/filepath" "strings" ) func readFile(file *zip.File) { // Open the file inside the zip rc, err := file.Open() if err != nil { log.Fatal(err) } defer rc.Close() // Read the contents of the file contents, err := ioutil.ReadAll(rc) // deprecated? :/ if err != nil { log.Fatal(err) } // Print the contents fmt.Printf("Contents of %s:\n", file.Name) fmt.Println(string(contents)) } func run(path string) { // Open the zip file r, err := zip.OpenReader(path) if err != nil { log.Fatal(err) } defer r.Close() // Iterate through the files in the zip archive fmt.Println("JavaScript files in the zip archive:") for _, f := range r.File { // Use filepath.Ext to check the file extension if strings.HasPrefix(f.Name, "data/") && strings.ToLower(filepath.Ext(f.Name)) == ".js" { readFile(f) return // Exit after processing the first .js file so we don't end up printing a gazillion lines when testing } } } func main() { // Example usage if len(os.Args) < 2 { log.Fatal("Please provide the path to the zip file as an argument.") } path:= os.Args[1] run(path) }
Wir haben die strukturierten Daten gefunden. Jetzt müssen wir es analysieren. Die gute Nachricht ist, dass es bereits Pakete für die Verwendung von JavaScript in Go gibt. Wir werden Goja verwenden.
Wenn Sie sich in diesem Abschnitt befinden, mit Goja vertraut sind und die Ausgabe der Datei gesehen haben, werden Sie möglicherweise feststellen, dass wir in Zukunft Fehler haben werden.
Goja installieren:
go get github.com/dop251/goja
Jetzt bearbeiten wir die Datei main.go, um Folgendes zu tun:
package main import ( "archive/zip" "fmt" "io/ioutil" "log" "os" "path/filepath" "strings" ) func readFile(file *zip.File) { // Open the file inside the zip rc, err := file.Open() if err != nil { log.Fatal(err) } defer rc.Close() // Read the contents of the file contents, err := ioutil.ReadAll(rc) // deprecated? :/ if err != nil { log.Fatal(err) } // Parse the JavaScript file using goja vm := goja.New() _, err = vm.RunString(contents) if err != nil { log.Fatalf("Error parsing JS file: %v", err) } fmt.Printf("Parsed JavaScript file: %s\n", file.Name) } func run(path string) { // Open the zip file r, err := zip.OpenReader(path) if err != nil { log.Fatal(err) } defer r.Close() // Iterate through the files in the zip archive fmt.Println("JavaScript files in the zip archive:") for _, f := range r.File { // Use filepath.Ext to check the file extension if strings.HasPrefix(f.Name, "data/") && strings.ToLower(filepath.Ext(f.Name)) == ".js" { readFile(f) return // Exit after processing the first .js file so we don't end up printing a gazillion lines when testing } } } func main() { // Example usage if len(os.Args) < 2 { log.Fatal("Please provide the path to the zip file as an argument.") } path:= os.Args[1] run(path) }
ÜBERRASCHUNG. „Fenster ist nicht definiert“ könnte ein bekannter Fehler sein. Grundsätzlich führt Goja eine EMCA-Laufzeit aus. Fenster ist Browserkontext und leider nicht verfügbar.
Zu diesem Zeitpunkt hatte ich einige Probleme. Einschließlich der Tatsache, dass keine Daten zurückgegeben werden können, da es sich um eine JS-Datei der obersten Ebene handelt.
Kurz gesagt, wir müssen den Inhalt der Dateien ändern, bevor wir sie in die Laufzeit laden.
Ändern wir die Datei main.go;
package main import ( "archive/zip" "fmt" "io/ioutil" "log" "os" "path/filepath" "regexp" "strings" "github.com/dop251/goja" ) func readFile(file *zip.File) { // Open the file inside the zip rc, err := file.Open() if err != nil { log.Fatal(err) } defer rc.Close() // Read the contents of the file contents, err := ioutil.ReadAll(rc) if err != nil { log.Fatal(err) } // Regular expressions to replace specific patterns reConfig := regexp.MustCompile(`window\.\w+\s*=\s*{`) reArray := regexp.MustCompile(`window\.\w+\.\w+\.\w+\s*=\s*\[`) // Replace patterns in the content processedContents := reConfig.ReplaceAllStringFunc(string(contents), func(s string) string { return "var data = {" }) processedContents = reArray.ReplaceAllStringFunc(processedContents, func(s string) string { return "var data = [" }) // Parse the JavaScript file using goja vm := goja.New() _, err = vm.RunString(processedContents) if err != nil { log.Fatalf("Error parsing JS file: %v", err) } // Retrieve the value of the 'data' variable from the JavaScript context value := vm.Get("data") if value == nil { log.Fatalf("No data variable found in the JS file") } // Output the parsed data fmt.Printf("Processed JavaScript file: %s\n", file.Name) fmt.Printf("Data extracted: %v\n", value.Export()) } func run(path string) { // Open the zip file r, err := zip.OpenReader(path) if err != nil { log.Fatal(err) } defer r.Close() // Iterate through the files in the zip archive for _, f := range r.File { // Check if the file is in the /data directory and has a .js extension if strings.HasPrefix(f.Name, "data/") && strings.ToLower(filepath.Ext(f.Name)) == ".js" { readFile(f) return // Exit after processing the first .js file so we don't end up printing a gazillion lines when testing } } } func main() { // Example usage if len(os.Args) < 2 { log.Fatal("Please provide the path to the zip file as an argument.") } path:= os.Args[1] run(path) }
Hurrah. Assuming I didn't muck up the copypaste into this post, you should now see a rather ugly print of the struct data from Go.
Edit the main.go file to marshall the JSON output.
package main import ( "archive/zip" "encoding/json" "fmt" "io/ioutil" "log" "os" "path/filepath" "regexp" "strings" "github.com/dop251/goja" ) func readFile(file *zip.File) { // Open the file inside the zip rc, err := file.Open() if err != nil { log.Fatal(err) } defer rc.Close() // Read the contents of the file contents, err := ioutil.ReadAll(rc) // deprecated :/ if err != nil { log.Fatal(err) } // Regular expressions to replace specific patterns reConfig := regexp.MustCompile(`window\.\w+\s*=\s*{`) reArray := regexp.MustCompile(`window\.\w+\.\w+\.\w+\s*=\s*\[`) // Replace patterns in the content processedContents := reConfig.ReplaceAllStringFunc(string(contents), func(s string) string { return "var data = {" }) processedContents = reArray.ReplaceAllStringFunc(processedContents, func(s string) string { return "var data = [" }) // Parse the JavaScript file using goja vm := goja.New() _, err = vm.RunString(processedContents) if err != nil { log.Fatalf("Error parsing JS file: %v", err) } // Retrieve the value of the 'data' variable from the JavaScript context value := vm.Get("data") if value == nil { log.Fatalf("No data variable found in the JS file") } // Convert the data to a Go-native type data := value.Export() // Marshal the Go-native type to JSON jsonData, err := json.MarshalIndent(data, "", " ") if err != nil { log.Fatalf("Error marshalling data to JSON: %v", err) } // Output the JSON data fmt.Println(string(jsonData)) } func run(zipFilePath string) { // Open the zip file r, err := zip.OpenReader(zipFilePath) if err != nil { log.Fatal(err) } defer r.Close() // Iterate through the files in the zip archive for _, f := range r.File { // Check if the file is in the /data directory and has a .js extension if strings.HasPrefix(f.Name, "data/") && strings.ToLower(filepath.Ext(f.Name)) == ".js" { readFile(f) return // Exit after processing the first .js file } } } func main() { // Example usage if len(os.Args) < 2 { log.Fatal("Please provide the path to the zip file as an argument.") } zipFilePath := os.Args[1] run(zipFilePath) }
That's it!
go run main.go twitter.zip
} "userInfo": { "accountId": "1234567890", "displayName": "Luke ✨", "userName": "lukeocodes" } }
I'll be open sourcing a lot of this work so that others who want to parse the data from the archive, can store it how they like.
Das obige ist der detaillierte Inhalt vonZeit zu gehen? Zeit zum Wiederaufbau! Twitter machen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!