Musk와 Twitter에 지친 사용자를 위한 새로운 소셜 네트워크의 가장 중요한 기능은 다음과 같습니다.
덜 중요하지만 확실히 유용한 플랫폼 기능
이 게시물에서는 첫 번째 기능에 중점을 두겠습니다. 트위터 archive.zip 파일을 가져오는 중입니다.
Twitter에서는 데이터를 쉽게 얻을 수 있도록 만들지 않았습니다. 그들이 당신에게 그것에 대한 액세스를 제공한다는 것은 좋은 일입니다(법적으로는 그렇게 해야 합니다). 형식이 쓰레기네요.
실제로는 미니 웹 아카이브로 제공되며 모든 데이터는 JavaScript 파일에 갇혀 있습니다. 편리한 데이터 저장이라기보다 웹앱에 가깝습니다.
Your archive.html 파일을 열면 다음과 같은 내용이 나타납니다.
참고: 저는 사이트에 Next.js를 사용하고 백엔드에 Go와 GraphQL을 사용하여 구축하기로 꽤 일찍 결정했습니다.
그럼 데이터가 구조화된 데이터가 아닌 경우에는 어떻게 하나요?
글쎄요, 분석해 보세요.
Go를 시작하는 방법과 프로젝트 디렉터리를 설정하는 방법에 대한 공식 문서를 살펴보세요.
이 과정을 함께 해킹해보겠습니다. TwitterX에 너무 애착을 느끼는 사람들을 끌어들이는 가장 중요한 기능 중 하나인 것 같습니다.
첫 번째 단계는 main.go 파일을 만드는 것입니다. 이 파일에서 우리는 가서(하) 몇 가지 작업을 수행할 것입니다.
모든 단계에서 다음과 같이 파일을 실행합니다.
트위터 아카이브 내보내기가 없으면 간단한 매니페스트.js 파일을 만들고 다음 JavaScript를 제공하세요.
전체적으로 사용할 twitter.zip 파일로 압축하세요.
다음 단계는 zip 파일의 내용을 읽는 것입니다. 우리는 이 작업을 최대한 효율적으로 수행하고 디스크에서 데이터가 추출되는 시간을 줄이고 싶습니다.
zip에는 압축을 풀 필요가 없는 파일도 많습니다.
main.go 파일을 편집하겠습니다.
이 아카이브 파일은 심각하게 도움이 되지 않습니다. 우리는 .js 파일만 확인하고 /data 디렉터리에서만 확인하려고 합니다.
구조화된 데이터를 찾았습니다. 이제 이를 구문 분석해야 합니다. 좋은 소식은 Go 내부에서 JavaScript를 사용하기 위한 기존 패키지가 있다는 것입니다. 우리는 고자를 사용할 거예요
이 섹션에서 Goja에 익숙하고 파일의 출력을 본 적이 있다면 앞으로 오류가 발생할 것임을 알 수 있습니다.
고자 설치:
이제 main.go 파일을 편집하여 다음을 수행하겠습니다.
놀랐어요. window is not Defined(창이 정의되지 않았습니다)는 익숙한 오류일 수 있습니다. 기본적으로 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!