[https://github.com/imperatrona/twitter-scraper] Scrape the Twitter frontend API without authentication with Golang.
Find a file
dependabot[bot] c0e067d55e Bump golang.org/x/net from 0.11.0 to 0.17.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.11.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.11.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-11 22:49:30 +00:00
.github/workflows GetTrends required login 2023-07-07 13:20:05 +03:00
.gitignore add scrap tweets for any search query feature 2020-05-14 14:59:33 +02:00
api.go Add LoginOpenAccount 2023-05-30 17:31:00 +03:00
api_test.go Separate test package 2021-12-07 10:18:01 +02:00
auth.go Fix OpenAccount error handling 2023-09-16 11:49:07 +03:00
auth_test.go Improve skip auth test 2023-07-07 13:19:37 +03:00
go.mod Bump golang.org/x/net from 0.11.0 to 0.17.0 2023-10-11 22:49:30 +00:00
go.sum Bump golang.org/x/net from 0.11.0 to 0.17.0 2023-10-11 22:49:30 +00:00
LICENSE Add MIT license 2020-02-11 14:40:05 +02:00
profile.go improve request 2023-06-01 23:05:37 +03:00
profile_test.go Authentication is required! 2023-07-02 01:41:48 +03:00
README.md Fix typo 2023-07-12 00:30:08 +03:00
scraper.go Authentication is required! 2023-07-02 01:41:48 +03:00
search.go Use search GraphQL API 2023-07-03 14:38:46 +03:00
search_test.go Improve skip auth test 2023-07-07 13:19:37 +03:00
timeline_v1.go Authentication is required! 2023-07-02 01:41:48 +03:00
timeline_v2.go Fix runtime error 2023-07-03 14:57:29 +03:00
trends.go Use GraphQL API with timeline v2 2023-06-01 23:20:11 +03:00
trends_test.go GetTrends required login 2023-07-07 13:20:05 +03:00
tweets.go Authentication is required! 2023-07-02 01:41:48 +03:00
tweets_test.go Improve skip auth test 2023-07-07 13:19:37 +03:00
types.go Authentication is required! 2023-07-02 01:41:48 +03:00
util.go Use search GraphQL API 2023-07-03 14:38:46 +03:00

Twitter Scraper

Go Reference

Twitter's API is annoying to work with, and has lots of limitations — luckily their frontend (JavaScript) has it's own API, which I reverse-engineered. No API rate limits. No tokens needed. No restrictions. Extremely fast.

You can use this library to get the text of any user's Tweets trivially.

Installation

go get -u github.com/n0madic/twitter-scraper

Usage

Authentication

Now all methods require authentication!

Login

err := scraper.Login("username", "password")

Use username to login, not email! But if you have email confirmation, use email address in addition:

err := scraper.Login("username", "password", "email")

If you have two-factor authentication, use code:

err := scraper.Login("username", "password", "code")

Status of login can be checked with:

scraper.IsLoggedIn()

Logout (clear session):

scraper.Logout()

If you want save session between restarts, you can save cookies with scraper.GetCookies() and restore with scraper.SetCookies().

For example, save cookies:

cookies := scraper.GetCookies()
// serialize to JSON
js, _ := json.Marshal(cookies)
// save to file
f, _ = os.Create("cookies.json")
f.Write(js)

and load cookies:

f, _ := os.Open("cookies.json")
// deserialize from JSON
var cookies []*http.Cookie
json.NewDecoder(f).Decode(&cookies)
// load cookies
scraper.SetCookies(cookies)
// check login status
scraper.IsLoggedIn()

Open account

If you don't want to use your account, you can try login as a Twitter app:

err := scraper.LoginOpenAccount()

Get user tweets

package main

import (
    "context"
    "fmt"
    twitterscraper "github.com/n0madic/twitter-scraper"
)

func main() {
    scraper := twitterscraper.New()
    err := scraper.LoginOpenAccount()
    if err != nil {
        panic(err)
    }
    for tweet := range scraper.GetTweets(context.Background(), "Twitter", 50) {
        if tweet.Error != nil {
            panic(tweet.Error)
        }
        fmt.Println(tweet.Text)
    }
}

It appears you can ask for up to 50 tweets.

Get single tweet

package main

import (
    "fmt"

    twitterscraper "github.com/n0madic/twitter-scraper"
)

func main() {
    scraper := twitterscraper.New()
    err := scraper.Login(username, password)
    if err != nil {
        panic(err)
    }
    tweet, err := scraper.GetTweet("1328684389388185600")
    if err != nil {
        panic(err)
    }
    fmt.Println(tweet.Text)
}

Search tweets by query standard operators

Now the search only works for authenticated users!

Tweets containing “twitter” and “scraper” and “data“, filtering out retweets:

package main

import (
    "context"
    "fmt"
    twitterscraper "github.com/n0madic/twitter-scraper"
)

func main() {
    scraper := twitterscraper.New()
    err := scraper.Login(username, password)
    if err != nil {
        panic(err)
    }
    for tweet := range scraper.SearchTweets(context.Background(),
        "twitter scraper data -filter:retweets", 50) {
        if tweet.Error != nil {
            panic(tweet.Error)
        }
        fmt.Println(tweet.Text)
    }
}

The search ends if we have 50 tweets.

See Rules and filtering for build standard queries.

Set search mode

scraper.SetSearchMode(twitterscraper.SearchLatest)

Options:

  • twitterscraper.SearchTop - default mode
  • twitterscraper.SearchLatest - live mode
  • twitterscraper.SearchPhotos - image mode
  • twitterscraper.SearchVideos - video mode
  • twitterscraper.SearchUsers - user mode

Get profile

package main

import (
    "fmt"
    twitterscraper "github.com/n0madic/twitter-scraper"
)

func main() {
    scraper := twitterscraper.New()
    scraper.LoginOpenAccount()
    profile, err := scraper.GetProfile("Twitter")
    if err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", profile)
}

Search profiles by query

package main

import (
    "context"
    "fmt"
    twitterscraper "github.com/n0madic/twitter-scraper"
)

func main() {
    scraper := twitterscraper.New().SetSearchMode(twitterscraper.SearchUsers)
    err := scraper.Login(username, password)
    if err != nil {
        panic(err)
    }
    for profile := range scraper.SearchProfiles(context.Background(), "Twitter", 50) {
        if profile.Error != nil {
            panic(profile.Error)
        }
        fmt.Println(profile.Name)
    }
}
package main

import (
    "fmt"
    twitterscraper "github.com/n0madic/twitter-scraper"
)

func main() {
    scraper := twitterscraper.New()
    trends, err := scraper.GetTrends()
    if err != nil {
        panic(err)
    }
    fmt.Println(trends)
}

Use Proxy

Support HTTP(s) and SOCKS5 proxy

with HTTP

err := scraper.SetProxy("http://localhost:3128")
if err != nil {
    panic(err)
}

with SOCKS5

err := scraper.SetProxy("socks5://localhost:1080")
if err != nil {
    panic(err)
}

Delay requests

Add delay between API requests (in seconds)

scraper.WithDelay(5)

Load timeline with tweet replies

scraper.WithReplies(true)