Maison > Article > développement back-end > Il est temps de partir ? Il est temps de reconstruire ! Créer Twitter
Les fonctionnalités les plus critiques d'un nouveau réseau social pour les utilisateurs qui en ont assez de Musk et de Twitter sont les suivantes :
Fonctionnalités moins critiques mais certainement utiles de la plateforme ;
Dans cet article, nous nous concentrerons sur la première fonctionnalité. Importation du fichier archive.zip de Twitter.
Twitter n'a pas rendu vos données aussi faciles à obtenir. C'est génial qu'ils vous y donnent accès (légalement, ils le doivent). Le format est nul.
Il s'agit en fait d'une mini archive Web et toutes vos données sont bloquées dans des fichiers JavaScript. Il s'agit plus d'une application Web que d'un stockage pratique de données.
Lorsque vous ouvrez le fichier Your archive.html, vous obtenez quelque chose comme ceci ;
Remarque : j'ai pris la décision assez tôt de construire en utilisant Next.js pour le site, Go et GraphQL pour le backend.
Alors, que faites-vous lorsque vos données ne sont pas des données structurées ?
Eh bien, vous l'analysez.
Rendez-vous à la documentation officielle pour savoir comment démarrer avec Go et configurer le répertoire de votre projet.
Nous allons pirater ce processus ensemble. Cela semble être l'une des fonctionnalités les plus importantes pour attirer les personnes qui se sentent trop attachées à TwitterX.
La première étape consiste à créer un fichier main.go. Dans ce fichier, nous allons ALLER (hah) et faire quelques trucs ;
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) }
À chaque étape, nous exécuterons le fichier comme ceci ;
go run main.go twitter.zip
Si vous n'avez pas d'exportation d'archive Twitter, créez un simple fichier manifest.js et donnez-lui le JavaScript suivant.
window.__THAR_CONFIG = { "userInfo" : { "accountId" : "1234567890", "userName" : "lukeocodes", "displayName" : "Luke ✨" }, };
Compressez-le dans votre fichier twitter.zip que nous utiliserons tout au long.
L'étape suivante consiste à lire le contenu du fichier zip. Nous voulons le faire aussi efficacement que possible et réduire le temps d'extraction des données sur le disque.
Il y a de nombreux fichiers dans le zip qui n'ont pas non plus besoin d'être extraits.
Nous modifierons le fichier 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) }
Ce fichier d'archive est vraiment inutile. Nous voulons vérifier uniquement les fichiers .js, et uniquement dans le répertoire /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) }
Nous avons trouvé les données structurées. Nous devons maintenant l'analyser. La bonne nouvelle est qu’il existe des packages permettant d’utiliser JavaScript dans Go. Nous utiliserons du goja.
Si vous êtes dans cette section, familier avec Goja, et que vous avez vu la sortie du fichier, vous verrez peut-être que nous aurons des erreurs dans notre futur.
Installer goja :
go get github.com/dop251/goja
Nous allons maintenant modifier le fichier main.go pour effectuer les opérations suivantes :
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) }
SUPRISE. la fenêtre n'est pas définie peut être une erreur familière. Fondamentalement, goja exécute un runtime EMCA. la fenêtre est le contexte du navigateur et malheureusement indisponible.
J'ai rencontré quelques problèmes à ce stade. Y compris l'impossibilité de renvoyer des données car il s'agit d'un fichier JS de premier niveau.
Pour faire court, nous devons modifier le contenu des fichiers avant de les charger dans le runtime.
Modifions le fichier 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.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!