[https://github.com/imperatrona/twitter-scraper] Scrape the Twitter frontend API without authentication with Golang.
Find a file
2024-07-09 06:55:38 +03:00
.github/workflows run test once a week 2024-07-09 02:05:05 +03:00
.vscode improve SetAuthToken input 2024-03-09 18:26:46 +03:00
.gitignore fix tests 2024-02-20 23:27:22 +03:00
api.go fix accept 200-299 status codes 2024-03-09 03:54:20 +03:00
api_test.go fix tests 2024-02-20 23:27:22 +03:00
auth.go improve SetAuthToken input 2024-03-09 18:26:46 +03:00
auth_test.go improve SetAuthToken input 2024-03-09 18:26:46 +03:00
bookmarks.go add bookmark method 2024-02-21 04:41:51 +03:00
bookmarks_test.go skip tests that requires auth 2024-03-08 19:23:39 +03:00
CHANGELOG.md add changelog 2024-07-09 06:55:38 +03:00
follows.go add followers method 2024-02-21 06:15:04 +03:00
follows_test.go skip tests that requires auth 2024-03-08 19:23:39 +03:00
go.mod bump deps 2024-03-09 14:54:49 +03:00
go.sum bump deps 2024-03-09 14:54:49 +03:00
LICENSE Add MIT license 2020-02-11 14:40:05 +02:00
medias.go add user media 2024-02-20 23:42:41 +03:00
medias_test.go skip tests that requires auth 2024-03-08 19:23:39 +03:00
profile.go add following & followed by to profile 2024-02-21 06:21:49 +03:00
profile_test.go fix test TestGetProfileErrorSuspended 2024-07-09 05:48:09 +03:00
README.md Merge pull request #6 from imperatrona/home 2024-07-09 06:11:33 +03:00
schedule.go added scheduling & media upload 2024-03-09 03:55:39 +03:00
schedule_test.go added scheduling & media upload 2024-03-09 03:55:39 +03:00
scraper.go fix socks proxy without auth 2024-02-20 23:42:41 +03:00
search.go fix nsfw for FetchSearchTweets 2024-04-26 00:29:36 +03:00
search_test.go update package name 2024-01-28 23:06:45 +03:00
timeline_v1.go Authentication is required! 2023-07-02 01:41:48 +03:00
timeline_v2.go fix nsfw for FetchTweets 2024-04-25 23:48:41 +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
tweet.go fix creating tweet with media 2024-07-09 02:54:38 +03:00
tweet_test.go fix creating tweet with media 2024-07-09 02:54:38 +03:00
tweets.go fix fetch home methods 2024-07-09 05:37:03 +03:00
tweets_test.go Merge pull request #6 from imperatrona/home 2024-07-09 06:11:33 +03:00
types.go add HLSURL to Video 2024-04-26 01:13:39 +03:00
upload.go added scheduling & media upload 2024-03-09 03:55:39 +03:00
upload_test.go added scheduling & media upload 2024-03-09 03:55:39 +03:00
util.go add HLSURL to Video 2024-04-26 01:13:39 +03:00

Twitter Scraper

Go Reference Go

Twitters API is pricey and has lots of limitations. But their frontend has its own API, which was reverse-engineered by @n0madic and maintained by @imperatrona. Some endpoints require authentication, but it is easy to scale by buying new accounts and proxies.

You can use this library to get tweets, profiles, and trends trivially.

Table of Contents

Installation

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

Quick start

package main

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

func main() {
    scraper := twitterscraper.New()
    scraper.SetAuthToken(twitterscraper.AuthToken{Token: "auth_token", CSRFToken: "ct0"})

    // After setting Cookies or AuthToken you have to execute IsLoggedIn method.
    // Without it, scraper wouldn't be able to make requests that requires authentication
    if !scraper.IsLoggedIn() {
      panic("Invalid AuthToken")
    }

    for tweet := range scraper.GetTweets(context.Background(), "x", 50) {
        if tweet.Error != nil {
            panic(tweet.Error)
        }
        fmt.Println(tweet.Text)
    }
}

Rate limits

Api has a global limit on how many requests per second are allowed, dont make requests more than once per 1.5 seconds from one account. Also each endpoint has its own limits, most of them are 150 requests per 15 minutes.

Apparently twitter doesnt limit the number of accounts that can be used per one IP address. This could change at any time. As of February 2024, I have been managing 20 accounts per IP address without receiving a ban for several months.

OpenAccount was great in the past, but now its nerfed by twitter. They allow 180 requests instead of 150, but you can only create one account per month with one IP address. If you use OpenAccount you should save your credentials and use them later with WithOpenAccount method.

Authentication

Most endpoints require authentication. The preferable way is to use SetCookies. You can also use SetAuthToken but POST endpoints will not work. Login with password may require confirmation with email and is often the reason of accounts ban.

Endpoints that work without authentication will not return sensitive content. To get sensitive content you need to authenticate with any available method including OpenAccount.

Using cookies

// Deserialize from JSON
var cookies []*http.Cookie
f, _ := os.Open("cookies.json")
json.NewDecoder(f).Decode(&cookies)

scraper.SetCookies(cookies)
if !scraper.IsLoggedIn() {
    panic("Invalid cookies")
}

To save cookies from an authorized client to a file, use GetCookies:

cookies := scraper.GetCookies()

data, _ := json.Marshal(cookies)
f, _ = os.Create("cookies.json")
f.Write(data)

Using AuthToken

SetAuthToken method simply set required cookies auth_token and ct0.

scraper.SetAuthToken(twitterscraper.AuthToken{Token: "auth_token", CSRFToken: "ct0"})
if !scraper.IsLoggedIn() {
    panic("Invalid AuthToken")
}

OpenAccount

Warning

Deprecated. Nerfed by twitter, doesn't support new endpoints.

LoginOpenAccount is now limited to one new account per month for IP address.

account, err := scraper.LoginOpenAccount()

You should save OpenAccount returned by LoginOpenAccount to reuse it later.

scraper.WithOpenAccount(twitterscraper.OpenAccount{
    OAuthToken: "TOKEN",
    OAuthTokenSecret: "TOKEN_SECRET",
})

Login & Password

To log in, you have to use your username, not the email!

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

If you have email confirmation, use your email address in addition:

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

If you have two-factor authentication, use the code:

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

Check if login

Status of login can be checked with method IsLoggedIn:

scraper.IsLoggedIn()

Log out

scraper.Logout()

Methods

Get tweet

150 requests / 15 minutes

TweetDetail endpoint requires auth, so TweetResultByRestId endpoint used instead when auth not provided. Which doesn't return InReplyToStatus and Thread tweets.

tweet, err := scraper.GetTweet("1328684389388185600")

Get user tweets

150 requests / 15 minutes

GetTweets returns a channel with the specified number of user tweets. Its using the FetchTweets method under the hood.

for tweet := range scraper.GetTweets(context.Background(), "taylorswift13", 50) {
    if tweet.Error != nil {
        panic(tweet.Error)
    }
    fmt.Println(tweet.Text)
}

FetchTweets returns tweets and cursor for fetching the next page. Each request returns up to 20 tweets.

var cursor string
tweets, cursor, err := scraper.FetchTweets("taylorswift13", 20, cursor)

Get user medias

500 requests / 15 minutes

GetMediaTweets returns a channel with the specified number of user tweets that contain media. Its using the FetchMediaTweets method under the hood.

for tweet := range scraper.GetMediaTweets(context.Background(), "taylorswift13", 50) {
    if tweet.Error != nil {
        panic(tweet.Error)
    }
    fmt.Println(tweet.Text)
}

FetchMediaTweets returns tweets and cursor for fetching the next page. Each request returns up to 20 tweets.

var cursor string
tweets, cursor, err := scraper.FetchMediaTweets("taylorswift13", 20, cursor)

Get bookmarks

Important

Requires authentication!

500 requests / 15 minutes

GetBookmarks returns a channel with the specified number of bookmarked tweets. Its using the FetchBookmarks method under the hood.

for tweet := range scraper.GetBookmarks(context.Background(), 50) {
    if tweet.Error != nil {
        panic(tweet.Error)
    }
    fmt.Println(tweet.Text)
}

FetchBookmarks returns bookmarked tweets and cursor for fetching the next page. Each request returns up to 20 tweets.

var cursor string
tweets, cursor, err := scraper.FetchBookmarks(20, cursor)

Get home tweets

Important

Requires authentication!

500 requests / 15 minutes

GetHomeTweets returns a channel with the specified number of latest home tweets. Its using the FetchHomeTweets method under the hood.

for tweet := range scraper.GetHomeTweets(context.Background(), 50) {
    if tweet.Error != nil {
        panic(tweet.Error)
    }
    fmt.Println(tweet.Text)
}

FetchHomeTweets returns latest home tweets and cursor for fetching the next page. Each request returns up to 20 tweets.

var cursor string
tweets, cursor, err := scraper.FetchHomeTweets(20, cursor)

Get foryou tweets

Important

Requires authentication!

500 requests / 15 minutes

GetForYouTweets returns a channel with the specified number of for you home tweets. Its using the FetchForYouTweets method under the hood.

for tweet := range scraper.GetForYouTweets(context.Background(), 50) {
    if tweet.Error != nil {
        panic(tweet.Error)
    }
    fmt.Println(tweet.Text)
}

FetchForYouTweets returns for you home tweets and cursor for fetching the next page. Each request returns up to 20 tweets.

var cursor string
tweets, cursor, err := scraper.FetchForYouTweets(20, cursor)

Search tweets

Important

Requires authentication!

150 requests / 15 minutes

SearchTweets returns a channel with the specified number of tweets that contain media. Its using the FetchSearchTweets method under the hood.

for tweet := range scraper.SearchTweets(context.Background(),
    "twitter scraper data -filter:retweets", 50) {
    if tweet.Error != nil {
        panic(tweet.Error)
    }
    fmt.Println(tweet.Text)
}

FetchSearchTweets returns tweets and cursor for fetching the next page. Each request returns up to 20 tweets.

tweets, cursor, err := scraper.FetchSearchTweets("taylorswift13", 20, cursor)

By default, search returns top tweets. You can change it by specifying the search mode before making requests. Supported modes are SearchTop, SearchLatest, SearchPhotos, SearchVideos, and SearchUsers.

scraper.SetSearchMode(twitterscraper.SearchLatest)

Search params

See Rules and filtering for build standard queries.

Get profile

95 requests / 15 minutes

profile, err := scraper.GetProfile("taylorswift13")

Search profile

Important

Requires authentication!

150 requests / 15 minutes

SearchProfiles returns a channel with the specified number of tweets that contain media. Its using the FetchSearchProfiles method under the hood.

for profile := range scraper.SearchProfiles(context.Background(), "Twitter", 50) {
    if profile.Error != nil {
        panic(profile.Error)
    }
    fmt.Println(profile.Name)
}

FetchSearchProfiles returns profiles and cursor for fetching the next page. Each request returns up to 20 tweets.

profiles, cursor, err := scraper.FetchSearchProfiles("taylorswift13", 20, cursor)
trends, err := scraper.GetTrends()

Get following

Important

Requires authentication!

500 requests / 15 minutes

var cursor string
users, cursor, err := scraper.FetchFollowing("Support", 20, cursor)

Get followers

Important

Requires authentication!

50 requests / 15 minutes

var cursor string
users, cursor, err := scraper.FetchFollowers("Support", 20, cursor)

Create tweet

Important

Requires authentication!

tweet, err = scraper.CreateTweet(twitterscraper.NewTweet{
    Text:   "new tweet text",
    Medias: nil,
})

To create tweet with medias, you need to upload media first. Up to 4 medias; jpg, mp4 and gif allowed.

var media *twitterscraper.Media
media, err = testScraper.UploadMedia("./photo.jpg")
if err != nil {
    t.Error(err)
}
tweet, err = scraper.CreateTweet(twitterscraper.NewTweet{
    Text:   "new tweet text",
    Medias: []*twitterscraper.Media{
        media,
    },
})

Delete tweet

Important

Requires authentication!

err := testScraper.DeleteTweet("1810458885008105870");

Create retweet

Important

Requires authentication!

Returns retweet id, which is not the same as source tweet id.

retweetId, err := testScraper.CreateRetweet("1792634158977568997");

Delete retweet

Important

Requires authentication!

To delete retweet use source tweet id instead retweet id.

err := testScraper.DeleteRetweet("1792634158977568997");

Get scheduled tweets

Important

Requires authentication!

500 requests / 15 minutes

tweets, err := scraper.FetchScheduledTweets()

Create scheduled tweet

Important

Requires authentication!

500 requests / 15 minutes

tweets, err := scraper.CreateScheduledTweet(twitterscraper.TweetSchedule{
    Text:   "New scheduled tweet text",
    Date:   time.Now().Add(time.Hour * 24 * 31),
    Medias: nil,
})

Delete scheduled tweet

Important

Requires authentication!

500 requests / 15 minutes

err := scraper.DeleteScheduledTweet("123")

Upload media

Important

Requires authentication!

50 requests / 15 minutes

Uploads photo, video or gif for further posting or scheduling. Expires in 24 hours if not used.

media, err := scraper.UploadMedia("./files/movie.mp4")

Connection

Proxy

HTTP(s)

err := scraper.SetProxy("http://localhost:3128")

SOCKS5

err := scraper.SetProxy("socks5://localhost:1080")

Socks5 proxy support authentication.

err := scraper.SetProxy("socks5://user:pass@localhost:1080")

Delay

Add delay between API requests (in seconds)

scraper.WithDelay(5)

Load timeline with tweet replies

scraper.WithReplies(true)

Contributing

Testing

To run some tests, you need to set any form of authentication via environment variables. You can see all possible variables in .vscode/settings.json file. You can also set them in the file to use automatically in vscode, just make sure you dont commit them in your contribution.