マスクと Twitter にうんざりしているユーザーにとって、新しいソーシャル ネットワークの最も重要な機能は次のとおりです。
それほど重要ではありませんが、間違いなく役立つプラットフォームの機能です。
この投稿では、最初の機能に焦点を当てます。 Twitter の archive.zip ファイルをインポートしています。
Twitter では、データをそれほど簡単に入手できるわけではありません。彼らがあなたにそれにアクセスできるようにするのは素晴らしいことです(法的にはそうしなければなりません)。フォーマットがクソだ。
実際にはミニ Web アーカイブとして提供され、すべてのデータは JavaScript ファイルに保存されます。これは、データの便利なストレージというよりは、Web アプリに近いものです。
Your archive.html ファイルを開くと、次のような内容が表示されます。
注: 私はかなり早い段階で、サイトには Next.js を使用し、バックエンドには Go と GraphQL を使用して構築することを決定しました。
では、データが構造化データではない場合はどうすればよいでしょうか?
まあ、あなたはそれを解析します。
Go の開始方法に関する公式ドキュメントに進み、プロジェクト ディレクトリを設定してください。
私たちはこのプロセスを一緒にハックしていきます。これは、TwitterX に愛着を感じすぎる人々を惹きつける最も重要な機能の 1 つであるようです。
最初のステップは、main.go ファイルを作成することです。このファイルでは、 (笑) いくつかの作業を行います。
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) }
各ステップで、次のようにファイルを実行します。
go run main.go twitter.zip
Twitter アーカイブのエクスポートがない場合は、単純な manifest.js ファイルを作成し、次の JavaScript を指定します。
window.__THAR_CONFIG = { "userInfo" : { "accountId" : "1234567890", "userName" : "lukeocodes", "displayName" : "Luke ✨" }, };
それを twitter.zip ファイルに圧縮し、全体で使用します。
次のステップは、zip ファイルの内容を読み取ることです。これをできるだけ効率的に実行し、ディスク上でデータが抽出される時間を短縮したいと考えています。
zip 内には解凍する必要のないファイルも多数あります。
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) }
このアーカイブ ファイルはまったく役に立ちません。 /data ディレクトリ内の .js ファイルのみをチェックしたいと考えています。
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) }
構造化データを発見しました。次に、それを解析する必要があります。良いニュースは、Go 内で JavaScript を使用するための既存のパッケージがあることです。 gojaを使用します。
このセクションを読んでいて Goja に詳しく、ファイルの出力を見たことがあるなら、今後エラーが発生することがわかるかもしれません。
goja をインストールします:
go get github.com/dop251/goja
次に、main.go ファイルを編集して次のことを行います。
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) }
驚きました。 「ウィンドウが定義されていません」はよくあるエラーかもしれません。基本的に goja は EMCA ランタイムを実行します。ウィンドウはブラウザのコンテキストであるため、残念ながら利用できません。
この時点でいくつかの問題を解決しました。これには、トップレベルの JS ファイルであるためデータを返せないことも含まれます。
簡単に言えば、ファイルをランタイムにロードする前にファイルの内容を変更する必要があります。
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.
以上が出発の時間ですか?再構築する時が来ました!ツイッターを作るの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。