twitter-scrapper/README.md

685 lines
18 KiB
Markdown
Raw Normal View History

2018-11-29 17:33:44 +02:00
# Twitter Scraper
2024-03-09 04:43:58 +03:00
[![Go Reference](https://pkg.go.dev/badge/github.com/imperatrona/twitter-scraper.svg)](https://pkg.go.dev/github.com/imperatrona/twitter-scraper) [![Go](https://github.com/imperatrona/twitter-scraper/actions/workflows/go.yml/badge.svg?branch=master)](https://github.com/imperatrona/twitter-scraper/actions/workflows/go.yml)
2021-03-09 10:54:25 +02:00
2024-02-21 04:03:47 +03:00
Twitters API is pricey and has lots of limitations. But their frontend has its own API, which was reverse-engineered by [@n0madic](https://github.com/n0madic) and maintained by [@imperatrona](https://github.com/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.
<details>
<summary><h2>Table of Contents</h2></summary>
- [Installation](#installation)
- [Quick start](#quick-start)
- [Rate limits](#rate-limits)
2024-07-12 20:16:38 +03:00
- [Methods that returns channels](#methods-that-returns-channels)
2024-02-21 04:03:47 +03:00
- [Authentication](#authentication)
- [Using cookies](#using-cookies)
- [Using AuthToken](#using-authtoken)
- [OpenAccount](#openaccount)
- [Login & Password](#login--password)
- [Check if login](#check-if-login)
- [Log out](#log-out)
- [Methods](#methods)
- [Get tweet](#get-tweet)
2024-08-01 17:39:06 +03:00
- [Get tweet replies](#get-tweet-replies)
2024-08-05 18:05:02 +03:00
- [Get tweet retweeters](#get-tweet-retweeters)
2024-02-21 04:03:47 +03:00
- [Get user tweets](#get-user-tweets)
- [Get user medias](#get-user-medias)
2024-02-21 04:41:51 +03:00
- [Get bookmarks](#get-bookmarks)
2024-07-09 05:37:43 +03:00
- [Get home tweets](#get-home-tweets)
- [Get foryou tweets](#get-foryou-tweets)
2024-02-21 04:03:47 +03:00
- [Search tweets](#search-tweets)
- [Search params](#search-params)
- [Get profile](#get-profile)
- [Search profile](#search-profile)
- [Get trends](#get-trends)
2024-02-21 06:15:17 +03:00
- [Get following](#get-following)
- [Get followers](#get-followers)
2024-07-24 03:46:28 +03:00
- [Get space](#get-space)
2024-07-24 03:54:57 +03:00
- [Like tweet](#like-tweet)
- [Unlike tweet](#unlike-tweet)
2024-07-09 03:07:22 +03:00
- [Create tweet](#create-tweet)
- [Delete tweet](#delete-tweet)
2024-07-09 03:21:51 +03:00
- [Create retweet](#create-retweet)
2024-07-09 03:07:22 +03:00
- [Delete retweet](#delete-retweet)
2024-03-09 03:55:39 +03:00
- [Get scheduled tweets](#get-scheduled-tweets)
- [Create scheduled tweet](#create-scheduled-tweet)
- [Delete scheduled tweet](#delete-scheduled-tweet)
- [Upload media](#upload-media)
2024-02-21 04:03:47 +03:00
- [Connection](#connection)
- [Proxy](#proxy)
- [HTTP(s)](#https)
- [SOCKS5](#socks5)
- [Delay](#delay)
- [Load timeline with tweet replies](#load-timeline-with-tweet-replies)
- [Contributing](#contributing)
- [Testing](#testing)
</details>
2018-11-29 17:33:44 +02:00
2020-06-15 15:05:41 +03:00
## Installation
```shell
2024-01-28 23:06:45 +03:00
go get -u github.com/imperatrona/twitter-scraper
2020-06-15 15:05:41 +03:00
```
2024-02-21 04:03:47 +03:00
## Quick start
2018-11-29 17:33:44 +02:00
2024-02-21 04:03:47 +03:00
```golang
package main
2024-02-21 04:03:47 +03:00
import (
"context"
"fmt"
twitterscraper "github.com/imperatrona/twitter-scraper"
)
2024-02-21 04:03:47 +03:00
func main() {
scraper := twitterscraper.New()
2024-03-21 09:24:42 +03:00
scraper.SetAuthToken(twitterscraper.AuthToken{Token: "auth_token", CSRFToken: "ct0"})
2024-02-21 04:03:47 +03:00
// 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")
}
2024-02-21 04:03:47 +03:00
for tweet := range scraper.GetTweets(context.Background(), "x", 50) {
if tweet.Error != nil {
panic(tweet.Error)
}
fmt.Println(tweet.Text)
}
}
```
2024-02-21 04:03:47 +03:00
## Rate limits
2024-02-21 04:03:47 +03:00
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.
2024-02-21 04:03:47 +03:00
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.
2024-02-21 04:03:47 +03:00
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.
2024-07-12 20:16:38 +03:00
## Methods that returns channels
Some methods returns channels. They created to rid you from dealing with `cursor`, but under the hood they still using the same endpoints as they `Fetch` counterparts, they have the same rate limits. For example `GetTweets` using `FetchTweets` to get tweets. `FetchTweets` returns up to 20 tweets, so if you set `GetTweets` to fetch 150 tweets it will make 8 requests to `FetchTweets` (150/20=7.5 ~ 8 requests).
If under-hood `Fetch` method got the error, it will be passed to object `twitterscraper.TweetResult` and will stop further scraping. In methods that return `twitterscraper.TweetResult` you should check if `tweet.Error` is not `nil` before accessing the tweet content.
2024-02-21 04:03:47 +03:00
## 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.
2024-02-21 04:03:47 +03:00
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
```golang
2024-02-21 04:03:47 +03:00
// Deserialize from JSON
var cookies []*http.Cookie
f, _ := os.Open("cookies.json")
json.NewDecoder(f).Decode(&cookies)
2024-02-21 04:03:47 +03:00
scraper.SetCookies(cookies)
if !scraper.IsLoggedIn() {
panic("Invalid cookies")
}
```
2024-02-21 04:03:47 +03:00
To save cookies from an authorized client to a file, use `GetCookies`:
```golang
cookies := scraper.GetCookies()
2024-02-21 04:03:47 +03:00
data, _ := json.Marshal(cookies)
f, _ = os.Create("cookies.json")
2024-02-21 04:03:47 +03:00
f.Write(data)
```
2024-02-21 04:03:47 +03:00
### Using AuthToken
2024-03-09 18:26:46 +03:00
`SetAuthToken` method simply set required cookies `auth_token` and `ct0`.
```golang
2024-03-09 18:26:46 +03:00
scraper.SetAuthToken(twitterscraper.AuthToken{Token: "auth_token", CSRFToken: "ct0"})
2024-02-21 04:03:47 +03:00
if !scraper.IsLoggedIn() {
panic("Invalid AuthToken")
}
```
2024-02-21 04:03:47 +03:00
### OpenAccount
> [!WARNING]
> Deprecated. Nerfed by twitter, doesn't support new endpoints.
2024-02-21 04:03:47 +03:00
`LoginOpenAccount` is now limited to one new account per month for IP address.
```golang
2023-10-08 21:58:48 -03:00
account, err := scraper.LoginOpenAccount()
```
2024-02-21 04:03:47 +03:00
You should save `OpenAccount` returned by `LoginOpenAccount` to reuse it later.
2024-01-28 23:35:18 +03:00
```golang
scraper.WithOpenAccount(twitterscraper.OpenAccount{
OAuthToken: "TOKEN",
OAuthTokenSecret: "TOKEN_SECRET",
})
```
2024-02-21 04:03:47 +03:00
### Login & Password
To log in, you have to use your username, not the email!
2019-09-21 10:59:45 +03:00
2018-11-29 17:33:44 +02:00
```golang
2024-02-21 04:03:47 +03:00
err := scraper.Login("username", "password")
```
2018-11-29 17:33:44 +02:00
2024-02-21 04:03:47 +03:00
If you have email confirmation, use your email address in addition:
2018-11-29 17:33:44 +02:00
2024-02-21 04:03:47 +03:00
```golang
err := scraper.Login("username", "password", "email")
2018-11-29 17:33:44 +02:00
```
2024-02-21 04:03:47 +03:00
If you have two-factor authentication, use the code:
2018-11-29 17:33:44 +02:00
2024-02-21 04:03:47 +03:00
```golang
err := scraper.Login("username", "password", "code")
```
### Check if login
Status of login can be checked with method `IsLoggedIn`:
2024-02-13 04:45:08 +03:00
```golang
2024-02-21 04:03:47 +03:00
scraper.IsLoggedIn()
```
2024-02-13 04:45:08 +03:00
2024-02-21 04:03:47 +03:00
### Log out
2024-02-13 04:45:08 +03:00
2024-02-21 04:03:47 +03:00
```golang
scraper.Logout()
```
## Methods
### Get tweet
150 requests / 15 minutes
2024-03-08 19:37:25 +03:00
`TweetDetail` endpoint requires auth, so `TweetResultByRestId` endpoint used instead when auth not provided. Which doesn't return `InReplyToStatus` and `Thread` tweets.
2024-02-21 04:03:47 +03:00
```golang
tweet, err := scraper.GetTweet("1328684389388185600")
```
2024-08-01 17:39:06 +03:00
### Get tweet replies
150 requests / 15 minutes
Returns by ~5-10 tweets and multiple cursors one for each thread.
```golang
var cursor string
tweets, cursors, err := scraper.GetTweetReplies("1328684389388185600", cursor)
```
To get all replies and replies of replies for tweet you can iterate for all cursors. To get only direct replies check if `cursor.ThreadID` is equal your tweet id.
```golang
2024-08-05 18:05:02 +03:00
tweets, cursors, err := scraper.GetTweetReplies("1328684389388185600", "")
2024-08-01 17:39:06 +03:00
if err != nil {
panic(err)
}
for {
if len(cursors) > 0 {
var cursor *twitterscraper.ThreadCursor
cursor, cursors = cursors[0], cursors[1:]
2024-08-05 18:05:02 +03:00
moreTweets, moreCursors, err := scraper.GetTweetReplies(tweetId, cursor.Cursor)
2024-08-01 17:39:06 +03:00
if err != nil {
// you can check here if rate limited, await and repeat request
panic(err)
}
tweets = append(tweets, moreTweets...)
if len(moreCursors) > 0 {
cursors = append(cursors, moreCursors...)
}
} else {
break
}
}
```
2024-08-05 18:05:02 +03:00
### Get tweet retweeters
500 requests / 15 minutes
Returns a list of users who have retweeted the tweet.
```golang
var cursor string
retweeters, cursor, err := scraper.GetTweetRetweeters("1328684389388185600", 20, cursor)
```
2024-02-21 04:03:47 +03:00
### Get user tweets
150 requests / 15 minutes
2024-07-12 20:16:38 +03:00
`GetTweets` returns a channel with the specified number of user tweets. Its using the `FetchTweets` method under the hood. Read how this method works in [Methods that returns channels](#methods-that-returns-channels).
2024-02-21 04:03:47 +03:00
```golang
for tweet := range scraper.GetTweets(context.Background(), "taylorswift13", 50) {
if tweet.Error != nil {
panic(tweet.Error)
2024-02-13 04:45:08 +03:00
}
2024-02-21 04:03:47 +03:00
fmt.Println(tweet.Text)
2024-02-13 04:45:08 +03:00
}
```
2024-02-21 04:03:47 +03:00
FetchTweets returns tweets and cursor for fetching the next page. Each request returns up to 20 tweets.
2021-03-09 10:40:22 +02:00
```golang
2024-02-21 04:03:47 +03:00
var cursor string
tweets, cursor, err := scraper.FetchTweets("taylorswift13", 20, cursor)
```
2021-03-09 10:40:22 +02:00
2024-02-21 04:03:47 +03:00
### Get user medias
2021-03-09 10:40:22 +02:00
2024-02-21 04:03:47 +03:00
500 requests / 15 minutes
2021-03-09 10:40:22 +02:00
2024-07-12 20:16:38 +03:00
`GetMediaTweets` returns a channel with the specified number of user tweets that contain media. Its using the `FetchMediaTweets` method under the hood. Read how this method works in [Methods that returns channels](#methods-that-returns-channels).
2024-02-21 04:03:47 +03:00
```golang
for tweet := range scraper.GetMediaTweets(context.Background(), "taylorswift13", 50) {
if tweet.Error != nil {
panic(tweet.Error)
2021-03-09 10:40:22 +02:00
}
fmt.Println(tweet.Text)
}
```
2024-02-21 04:03:47 +03:00
`FetchMediaTweets` returns tweets and cursor for fetching the next page. Each request returns up to 20 tweets.
2024-02-21 04:03:47 +03:00
```golang
var cursor string
tweets, cursor, err := scraper.FetchMediaTweets("taylorswift13", 20, cursor)
```
2023-05-21 01:10:22 +03:00
2024-02-21 04:41:51 +03:00
### Get bookmarks
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes
2024-07-12 20:16:38 +03:00
`GetBookmarks` returns a channel with the specified number of bookmarked tweets. Its using the `FetchBookmarks` method under the hood. Read how this method works in [Methods that returns channels](#methods-that-returns-channels).
2024-02-21 04:41:51 +03:00
```golang
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.
```golang
var cursor string
tweets, cursor, err := scraper.FetchBookmarks(20, cursor)
```
2024-07-09 05:37:43 +03:00
### Get home tweets
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes
2024-07-12 20:16:38 +03:00
`GetHomeTweets` returns a channel with the specified number of latest home tweets. Its using the `FetchHomeTweets` method under the hood. Read how this method works in [Methods that returns channels](#methods-that-returns-channels).
2024-07-09 05:37:43 +03:00
```golang
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.
```golang
var cursor string
tweets, cursor, err := scraper.FetchHomeTweets(20, cursor)
```
### Get foryou tweets
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes
2024-07-12 20:16:38 +03:00
`GetForYouTweets` returns a channel with the specified number of for you home tweets. Its using the `FetchForYouTweets` method under the hood. Read how this method works in [Methods that returns channels](#methods-that-returns-channels).
2024-07-09 05:37:43 +03:00
```golang
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.
```golang
var cursor string
tweets, cursor, err := scraper.FetchForYouTweets(20, cursor)
```
2024-02-21 04:03:47 +03:00
### Search tweets
2024-02-21 04:03:47 +03:00
> [!IMPORTANT]
> Requires authentication!
2024-02-21 04:03:47 +03:00
150 requests / 15 minutes
2024-07-12 20:16:38 +03:00
`SearchTweets` returns a channel with the specified number of tweets that contain media. Its using the `FetchSearchTweets` method under the hood. Read how this method works in [Methods that returns channels](#methods-that-returns-channels).
2024-02-21 04:03:47 +03:00
```golang
for tweet := range scraper.SearchTweets(context.Background(),
"twitter scraper data -filter:retweets", 50) {
if tweet.Error != nil {
panic(tweet.Error)
}
2024-02-21 04:03:47 +03:00
fmt.Println(tweet.Text)
}
```
2020-12-04 15:08:33 +07:00
2024-02-21 04:03:47 +03:00
`FetchSearchTweets` returns tweets and cursor for fetching the next page. Each request returns up to 20 tweets.
2024-02-21 04:03:47 +03:00
```golang
tweets, cursor, err := scraper.FetchSearchTweets("taylorswift13", 20, cursor)
```
2020-12-23 19:53:48 +02:00
2024-02-21 04:03:47 +03:00
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`.
2020-12-23 19:53:48 +02:00
```golang
2020-12-23 19:53:48 +02:00
scraper.SetSearchMode(twitterscraper.SearchLatest)
```
2024-02-21 04:03:47 +03:00
#### Search params
2020-12-23 19:53:48 +02:00
2024-02-21 04:03:47 +03:00
See [Rules and filtering](https://developer.twitter.com/en/docs/tweets/rules-and-filtering/overview/standard-operators) for build standard queries.
2019-09-21 10:59:45 +03:00
### Get profile
2024-02-21 04:03:47 +03:00
95 requests / 15 minutes
2019-09-21 10:59:45 +03:00
2024-02-21 04:03:47 +03:00
```golang
profile, err := scraper.GetProfile("taylorswift13")
2019-09-21 10:59:45 +03:00
```
2024-02-21 04:03:47 +03:00
### Search profile
2024-02-21 04:03:47 +03:00
> [!IMPORTANT]
> Requires authentication!
2024-02-21 04:03:47 +03:00
150 requests / 15 minutes
2024-07-12 20:16:38 +03:00
`SearchProfiles` returns a channel with the specified number of tweets that contain media. Its using the `FetchSearchProfiles` method under the hood. Read how this method works in [Methods that returns channels](#methods-that-returns-channels).
2024-02-21 04:03:47 +03:00
```golang
for profile := range scraper.SearchProfiles(context.Background(), "Twitter", 50) {
if profile.Error != nil {
panic(profile.Error)
}
2024-02-21 04:03:47 +03:00
fmt.Println(profile.Name)
}
```
2024-02-21 04:03:47 +03:00
`FetchSearchProfiles` returns profiles and cursor for fetching the next page. Each request returns up to 20 tweets.
2020-02-12 10:45:19 +02:00
```golang
2024-02-21 04:03:47 +03:00
profiles, cursor, err := scraper.FetchSearchProfiles("taylorswift13", 20, cursor)
```
2020-02-12 10:45:19 +02:00
2024-02-21 04:03:47 +03:00
### Get trends
2020-02-12 10:45:19 +02:00
2024-02-21 04:03:47 +03:00
```golang
trends, err := scraper.GetTrends()
2020-02-12 10:45:19 +02:00
```
2024-02-21 06:15:17 +03:00
### Get following
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes
```golang
var cursor string
2024-03-09 03:55:39 +03:00
users, cursor, err := scraper.FetchFollowing("Support", 20, cursor)
2024-02-21 06:15:17 +03:00
```
### Get followers
> [!IMPORTANT]
> Requires authentication!
50 requests / 15 minutes
```golang
var cursor string
2024-03-09 03:55:39 +03:00
users, cursor, err := scraper.FetchFollowers("Support", 20, cursor)
```
2024-07-24 03:46:28 +03:00
### Get space
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes
Use to retrvie data about space and it's participants. You can get up to 1000 participants of space. If method returns less, it's probably because listeners is anonymous.
```golang
space, err := scraper.GetSpace("space_id")
```
You can get `space_id` from space url which can be retrived from tweet. For example:
```golang
tweet, err := testScraper.GetTweet("1815884577040445599")
if err != nil {
t.Fatal(err)
}
var spaceId string
spaceUrl := tweet.URLs[0] // https://twitter.com/i/spaces/1mnxeAMPEqqxX
if strings.HasPrefix(spaceUrl, "https://twitter.com/i/spaces/") {
spaceId = strings.Replace(spaceUrl, "https://twitter.com/i/spaces/", "", 1) // 1mnxeAMPEqqxX
}
space, err := scraper.GetSpace(spaceId)
```
2024-07-24 03:54:57 +03:00
### Like tweet
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes (combined with `UnlikeTweet` method)
```golang
err := scraper.LikeTweet("tweet_id")
```
### Unlike tweet
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes (combined with `LikeTweet` method)
```golang
err := scraper.UnlikeTweet("tweet_id")
```
2024-07-09 03:07:22 +03:00
### Create tweet
> [!IMPORTANT]
> Requires authentication!
```golang
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.
```golang
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!
```golang
err := testScraper.DeleteTweet("1810458885008105870");
```
2024-07-09 03:21:51 +03:00
### Create retweet
2024-07-09 03:07:22 +03:00
> [!IMPORTANT]
> Requires authentication!
Returns retweet id, which is not the same as source tweet id.
```golang
retweetId, err := testScraper.CreateRetweet("1792634158977568997");
```
### Delete retweet
> [!IMPORTANT]
> Requires authentication!
To delete retweet use source tweet id instead retweet id.
```golang
err := testScraper.DeleteRetweet("1792634158977568997");
```
2024-03-09 03:55:39 +03:00
### Get scheduled tweets
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes
```golang
tweets, err := scraper.FetchScheduledTweets()
```
### Create scheduled tweet
> [!IMPORTANT]
> Requires authentication!
500 requests / 15 minutes
```golang
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
```golang
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.
```golang
media, err := scraper.UploadMedia("./files/movie.mp4")
2024-02-21 06:15:17 +03:00
```
2024-02-21 04:03:47 +03:00
## Connection
2021-09-09 11:15:53 +08:00
2024-02-21 04:03:47 +03:00
### Proxy
2021-09-09 11:15:53 +08:00
2024-02-21 04:03:47 +03:00
#### HTTP(s)
```golang
2020-12-12 23:33:57 +02:00
err := scraper.SetProxy("http://localhost:3128")
```
2024-02-21 04:03:47 +03:00
#### SOCKS5
2021-09-09 11:15:53 +08:00
```golang
2021-09-13 17:30:46 +03:00
err := scraper.SetProxy("socks5://localhost:1080")
2021-09-09 11:15:53 +08:00
```
2024-02-21 04:03:47 +03:00
Socks5 proxy support authentication.
```golang
err := scraper.SetProxy("socks5://user:pass@localhost:1080")
```
### Delay
Add delay between API requests (in seconds)
```golang
scraper.WithDelay(5)
```
### Load timeline with tweet replies
```golang
2020-12-12 23:33:57 +02:00
scraper.WithReplies(true)
```
2024-02-21 04:03:47 +03:00
## 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.