Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
16ecd1d
Fix request with CSRFToken
cyrus07424 Jun 11, 2019
926b728
Change dependency library version to mavencentral jar's vesion
cyrus07424 Jun 12, 2019
cfdfad3
Add is_business_account flag support
cyrus07424 Jun 12, 2019
9d61903
Add method for get login user ID
cyrus07424 Jun 12, 2019
41bfeb2
Add request header parameters
cyrus07424 Jun 13, 2019
b8738b7
Add login request parameter, Add common request header
cyrus07424 Jun 14, 2019
7807d85
Fix getAccountById method causes NullPointerException
cyrus07424 Jun 14, 2019
597d0fe
Add error type parameter support on InstagramException
cyrus07424 Jun 19, 2019
4ab22d2
Add CHECKPOINT_REQUIRED error type
cyrus07424 Jun 21, 2019
220249b
Add TWO_FACTOR_REQUIRED error type
cyrus07424 Jun 21, 2019
d713b9b
Fix ErrorType specific logic
cyrus07424 Jun 22, 2019
e0cb1ca
Change Exception type
cyrus07424 Jun 26, 2019
74074af
Add RATE_LIMITED error type
cyrus07424 Jul 3, 2019
3ecba80
Bump org.eclipse.persistence.moxy from 2.7.0 to 2.7.6
dependabot-preview[bot] Feb 17, 2020
309f745
Bump maven-shade-plugin from 3.2.0 to 3.2.2
dependabot-preview[bot] Feb 17, 2020
e0c89dc
Bump hibernate-jpa-2.1-api from 1.0.0.Final to 1.0.2
dependabot-preview[bot] Feb 17, 2020
9f7bc6f
Bump dom-transformation from 1.1 to 1.2
dependabot-preview[bot] Feb 17, 2020
6c900d3
Merge pull request #1 from evosystem-jp/dependabot/maven/org.eclipse.…
cyrus07424 Feb 17, 2020
b5d8748
Merge pull request #2 from evosystem-jp/dependabot/maven/org.apache.m…
cyrus07424 Feb 17, 2020
a569bd6
Merge pull request #3 from evosystem-jp/dependabot/maven/org.hibernat…
cyrus07424 Feb 17, 2020
3dac266
Merge pull request #4 from evosystem-jp/dependabot/maven/com.github.i…
cyrus07424 Feb 17, 2020
9b3c1c4
Bump lombok from edge-SNAPSHOT to 1.18.12
dependabot-preview[bot] Feb 18, 2020
3758e59
Bump commons-beanutils from 1.9.3 to 1.9.4
dependabot-preview[bot] Feb 18, 2020
e4c7e0a
Bump okhttp from 3.2.0 to 4.4.0
dependabot-preview[bot] Feb 18, 2020
1aa7abc
Bump jaxb-api from 2.1 to 2.3.1
dependabot-preview[bot] Feb 18, 2020
0d133af
Bump junit from 4.12 to 4.13
dependabot-preview[bot] Feb 18, 2020
42acca9
Bump maven-compiler-plugin from 3.8.0 to 3.8.1
dependabot-preview[bot] Feb 18, 2020
6fa56bd
Bump logging-interceptor from 3.2.0 to 4.4.0
dependabot-preview[bot] Feb 18, 2020
4b3b454
Bump assertj-core from 3.11.1 to 3.15.0
dependabot-preview[bot] Feb 18, 2020
e3933d5
Merge pull request #5 from evosystem-jp/dependabot/maven/org.projectl…
cyrus07424 Feb 21, 2020
ce7cc6b
Merge pull request #6 from evosystem-jp/dependabot/maven/commons-bean…
cyrus07424 Feb 21, 2020
a9ebb50
Merge pull request #7 from evosystem-jp/dependabot/maven/com.squareup…
cyrus07424 Feb 21, 2020
2f5415c
Merge pull request #8 from evosystem-jp/dependabot/maven/javax.xml.bi…
cyrus07424 Feb 21, 2020
e245c46
Merge pull request #9 from evosystem-jp/dependabot/maven/junit-junit-…
cyrus07424 Feb 21, 2020
605403b
Merge pull request #10 from evosystem-jp/dependabot/maven/org.apache.…
cyrus07424 Feb 21, 2020
1956a11
Merge pull request #11 from evosystem-jp/dependabot/maven/com.squareu…
cyrus07424 Feb 21, 2020
5a40f2a
Merge pull request #12 from evosystem-jp/dependabot/maven/org.assertj…
cyrus07424 Feb 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
Expand All @@ -25,7 +25,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<version>3.2.2</version>
<configuration>
<filters>
<filter>
Expand Down Expand Up @@ -66,31 +66,31 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.12.0</version>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>edge-SNAPSHOT</version>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
<version>1.9.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.persistence/org.eclipse.persistence.moxy -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.5.0</version>
<version>2.7.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
<version>1.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
Expand All @@ -102,38 +102,38 @@
<dependency>
<groupId>com.github.igor-suhorukov</groupId>
<artifactId>dom-transformation</artifactId>
<version>1.1</version>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>3.11.0</version>
<version>4.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.11.1</version>
<version>3.15.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
<version>2.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ public interface AuthenticatedInsta extends AnonymousInsta {
PageObject<Account> getFollowers(long userId, int pageCount) throws IOException;

ActivityFeed getActivityFeed() throws IOException;

Long getLoginUserId();
}
22 changes: 22 additions & 0 deletions src/main/java/me/postaddict/instagram/scraper/ErrorType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package me.postaddict.instagram.scraper;

public enum ErrorType {

CHECKPOINT_REQUIRED,

TWO_FACTOR_REQUIRED,

UNAUTHORIZED,

TEMPORARY_ACTION_BLOCKED,

ACTION_BLOCKED,

FOLLOWING_THE_MAX_LIMIT_OF_ACCOUNTS,

RATE_LIMITED,

INSTAGRAM_SERVER_ERROR,

UNKNOWN_ERROR
}
33 changes: 29 additions & 4 deletions src/main/java/me/postaddict/instagram/scraper/Instagram.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
import me.postaddict.instagram.scraper.request.parameters.MediaCode;
import me.postaddict.instagram.scraper.request.parameters.TagName;
import me.postaddict.instagram.scraper.request.parameters.UserParameter;
import okhttp3.Cookie;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
Expand All @@ -53,8 +55,10 @@ public Instagram(OkHttpClient httpClient) {

protected Request withCsrfToken(Request request) {
return request.newBuilder()
.addHeader("X-CSRFToken", csrf_token)
.addHeader("X-CSRFToken", getCSRFToken())
.addHeader("X-Instagram-AJAX", (rollout_hash.isEmpty() ? "1" : rollout_hash))
.addHeader("X-Requested-With", "XMLHttpRequest")
.addHeader("X-IG-App-ID", "936619743392459")
.build();
}

Expand All @@ -76,6 +80,15 @@ private void getCSRFToken(ResponseBody body) throws IOException {
this.csrf_token=getToken("\"csrf_token\":\"",32,body.byteStream());
}

private String getCSRFToken() {
for (Cookie cookie : this.httpClient.cookieJar().loadForRequest(HttpUrl.parse(Endpoint.BASE_URL))) {
if ("csrftoken".equals(cookie.name())) {
return cookie.value();
}
}
return csrf_token;
}

private void getRolloutHash(ResponseBody body){
try {
this.rollout_hash=getToken("\"rollout_hash\":\"",12,body.byteStream());
Expand Down Expand Up @@ -107,18 +120,20 @@ public void login(String username, String password) throws IOException {
RequestBody formBody = new FormBody.Builder()
.add("username", username)
.add("password", password)
.add("queryParams", "{}")
.add("optIntoOneTap", "true")
.build();

Request request = new Request.Builder()
.url(Endpoint.LOGIN_URL)
.header(Endpoint.REFERER, Endpoint.BASE_URL + "/")
.header(Endpoint.REFERER, Endpoint.BASE_URL + "/accounts/login/")
.post(formBody)
.build();

Response response = executeHttpRequest(withCsrfToken(request));
try(InputStream jsonStream = response.body().byteStream()) {
if(!mapper.isAuthenticated(jsonStream)){
throw new InstagramAuthException("Credentials rejected by instagram");
throw new InstagramAuthException("Credentials rejected by instagram", ErrorType.UNAUTHORIZED);
}
}
}
Expand All @@ -130,7 +145,7 @@ public Account getAccountById(long id) throws IOException {
.build();
Response response = executeHttpRequest(withCsrfToken(request));
try(InputStream jsonStream = response.body().byteStream()) {
return getMediaByCode(mapper.getLastMediaShortCode(jsonStream)).getOwner();
return getAccountByUsername(getMediaByCode(mapper.getLastMediaShortCode(jsonStream)).getOwner().getUsername());
}
}

Expand Down Expand Up @@ -344,4 +359,14 @@ private void validateTagName(String tag) {
throw new IllegalArgumentException("Please provide non empty tag name that not starts with #");
}
}

@Override
public Long getLoginUserId() {
for (Cookie cookie : this.httpClient.cookieJar().loadForRequest(HttpUrl.parse(Endpoint.BASE_URL))) {
if ("ds_user_id".equals(cookie.name())) {
return Long.parseLong(cookie.value());
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import me.postaddict.instagram.scraper.cookie.CookieHashSet;
import me.postaddict.instagram.scraper.cookie.DefaultCookieJar;
import me.postaddict.instagram.scraper.interceptor.ErrorInterceptor;
import me.postaddict.instagram.scraper.interceptor.UserAgentInterceptor;
import me.postaddict.instagram.scraper.interceptor.FakeBrowserInterceptor;
import okhttp3.OkHttpClient;

import java.io.IOException;
Expand All @@ -16,7 +16,7 @@ public static Instagram getAuthenticatedInstagramClient(String login, String pas
throws IOException{

OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new UserAgentInterceptor(userAgent))
.addInterceptor(new FakeBrowserInterceptor(userAgent))
.addInterceptor(new ErrorInterceptor())
.cookieJar(new DefaultCookieJar(new CookieHashSet()))
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package me.postaddict.instagram.scraper.exception;

import me.postaddict.instagram.scraper.ErrorType;

public class InstagramAuthException extends InstagramException {

public InstagramAuthException(){}
public InstagramAuthException() {
}

public InstagramAuthException(String message) {
super(message);
super(message, ErrorType.UNKNOWN_ERROR);
}

public InstagramAuthException(String message, ErrorType errorType) {
super(message, errorType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,26 @@

import java.io.IOException;

import me.postaddict.instagram.scraper.ErrorType;

public class InstagramException extends IOException {

private ErrorType errorType;

public InstagramException() {
}

public InstagramException(String message) {
public InstagramException(String message, ErrorType errorType) {
super(message);
this.errorType = errorType;
}

public ErrorType getErrorType() {
return errorType;
}

@Override
public String getMessage() {
return super.getMessage() + " : " + getErrorType();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package me.postaddict.instagram.scraper.exception;

import me.postaddict.instagram.scraper.ErrorType;

public class InstagramNotFoundException extends InstagramException {

public InstagramNotFoundException() {
}

public InstagramNotFoundException(String message) {
super(message);
super(message, ErrorType.UNKNOWN_ERROR);
}

public InstagramNotFoundException(String message, ErrorType errorType) {
super(message, errorType);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.postaddict.instagram.scraper.interceptor;

import me.postaddict.instagram.scraper.ErrorType;
import me.postaddict.instagram.scraper.exception.InstagramAuthException;
import me.postaddict.instagram.scraper.exception.InstagramException;
import me.postaddict.instagram.scraper.exception.InstagramNotFoundException;
Expand All @@ -17,18 +18,43 @@ public Response intercept(Chain chain) throws IOException {
if (code == 200) {
return response;
} else {
String bodyString = String.valueOf(response.body().string());
response.body().close();
}

switch (code) {
case 401:
throw new InstagramAuthException("Unauthorized");
case 403:
throw new InstagramAuthException("Access denied");
case 404:
throw new InstagramNotFoundException("Resource does not exist");
default:
throw new InstagramException("Response code is "+ code + ".");
ErrorType errorType = ErrorType.UNKNOWN_ERROR;
switch (code) {
case 400:
if (bodyString.contains("Sorry, you're following the max limit of accounts.")) {
errorType = ErrorType.FOLLOWING_THE_MAX_LIMIT_OF_ACCOUNTS;
} else if (bodyString.contains("feedback_required") ||
bodyString.contains("Action Blocked") ||
bodyString.contains("\\u30d6\\u30ed\\u30c3\\u30af\\u3055\\u308c\\u3066\\u3044\\u307e\\u3059")) {
errorType = ErrorType.ACTION_BLOCKED;
} else if (bodyString.contains("checkpoint_required")) {
errorType = ErrorType.CHECKPOINT_REQUIRED;
} else if (bodyString.contains("two_factor_required")) {
errorType = ErrorType.TWO_FACTOR_REQUIRED;
}
throw new InstagramException("Bad Request", errorType);
case 401:
throw new InstagramAuthException("Unauthorized", ErrorType.UNAUTHORIZED);
case 403:
if (bodyString.contains("Please wait a few minutes before you try again.") ||
bodyString.contains("数分してからもう一度実行してください。")) {
errorType = ErrorType.TEMPORARY_ACTION_BLOCKED;
} else if (bodyString.contains("unauthorized")) {
errorType = ErrorType.UNAUTHORIZED;
}
throw new InstagramAuthException("Access denied", errorType);
case 404:
throw new InstagramNotFoundException("Resource does not exist", errorType);
case 429:
throw new InstagramException("Rate limited", ErrorType.RATE_LIMITED);
case 502:
throw new InstagramException("Bad Gateway", ErrorType.INSTAGRAM_SERVER_ERROR);
default:
throw new InstagramException("Response code is " + code + ".", errorType);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

import java.io.IOException;

public class UserAgentInterceptor implements Interceptor {
public class FakeBrowserInterceptor implements Interceptor {

private final String userAgent;

public UserAgentInterceptor(String userAgent) {
public FakeBrowserInterceptor(String userAgent) {
this.userAgent = userAgent;
}

Expand All @@ -23,6 +23,9 @@ public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request newRequest = originalRequest.newBuilder()
.header("User-Agent", userAgent)
.header("Accept", "*/*")
.header("Accept-Language", "ja,en-US;q=0.7,en;q=0.3")
.header("DNT", "1")
.build();
return chain.proceed(newRequest);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ public class Account {
@Transient
private PageObject<Media> media;
private Date lastUpdated = new Date();
private Boolean isBusinessAccount;
}
Loading