Rumah > Artikel > pembangunan bahagian belakang > Masa untuk Pergi? Masa untuk Membina Semula! Membuat Twitter
Ciri paling kritikal rangkaian sosial baharu untuk pengguna yang bosan dengan Musk dan Twitter, adalah seperti berikut;
Ciri platform yang kurang kritikal tetapi pasti membantu;
Dalam siaran ini, kami akan menumpukan pada ciri pertama. Mengimport fail archive.zip Twitter.
Twitter tidak menjadikan data anda begitu mudah untuk diperoleh. Sangat bagus bahawa mereka memberi anda akses kepadanya (secara sah, mereka perlu). Formatnya adalah omong kosong.
Ia sebenarnya datang sebagai arkib web mini dan semua data anda tersekat dalam fail JavaScript. Ia lebih kepada apl web berbanding penyimpanan data yang mudah.
Apabila anda membuka fail archive.html anda, anda mendapat sesuatu seperti ini;
Nota: Saya membuat keputusan agak awal untuk membina menggunakan Next.js untuk tapak, Go dan GraphQL untuk bahagian belakang.
Jadi, apakah yang anda lakukan apabila data anda bukan data berstruktur?
Nah, anda menghuraikannya.
Terus ke dokumen rasmi tentang cara memulakan Go, dan sediakan direktori projek anda.
Kami akan menggodam proses ini bersama-sama. Nampaknya salah satu ciri yang paling penting untuk menarik orang yang berasa terlalu terikat dengan TwitterX.
Langkah pertama ialah mencipta fail main.go. Dalam fail ini kita akan GO (hah) dan melakukan beberapa PERKARA;
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) }
Pada setiap langkah, kami akan menjalankan fail seperti itu;
go run main.go twitter.zip
Jika anda tidak mempunyai eksport arkib Twitter, buat fail manifest.js mudah dan berikan JavaScript berikut.
window.__THAR_CONFIG = { "userInfo" : { "accountId" : "1234567890", "userName" : "lukeocodes", "displayName" : "Luke ✨" }, };
Mampatkannya ke dalam fail twitter.zip anda yang akan kami gunakan sepanjang masa.
Langkah seterusnya ialah membaca kandungan fail zip. Kami mahu melakukan ini secekap mungkin dan mengurangkan masa data diekstrak pada cakera.
Terdapat banyak fail dalam zip yang tidak perlu diekstrak juga.
Kami akan mengedit fail 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) }
Fail arkib ini sangat tidak membantu. Kami ingin menyemak hanya fail .js dan hanya dalam direktori /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) }
Kami telah menemui data berstruktur. Sekarang kita perlu menghuraikannya. Berita baiknya ialah terdapat pakej sedia ada untuk menggunakan JavaScript di dalam Go. Kami akan menggunakan goja.
Jika anda berada di bahagian ini, biasa dengan Goja, dan anda telah melihat output fail, anda mungkin melihat kami akan mengalami ralat pada masa hadapan kami.
Pasang goja:
go get github.com/dop251/goja
Sekarang kita akan mengedit fail main.go untuk melakukan perkara berikut;
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) }
KEJUTAN. tetingkap tidak ditakrifkan mungkin ralat biasa. Pada asasnya goja menjalankan masa jalan EMCA. tetingkap ialah konteks penyemak imbas dan malangnya tidak tersedia.
Saya telah melalui beberapa isu pada ketika ini. Termasuk tidak dapat mengembalikan data kerana ia adalah fail JS peringkat teratas.
Pendek cerita, kita perlu mengubah suai kandungan fail sebelum memuatkannya ke dalam masa jalan.
Jom ubah suai fail 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.
Atas ialah kandungan terperinci Masa untuk Pergi? Masa untuk Membina Semula! Membuat Twitter. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!