지식

Jsoup 을 이용한 인스타그램 크롤링

애앨리 2020. 10. 23. 14:48

오랜만에 크롤링 다시 접근
인스타그램 api 이용해서 가져오는건 해봤는데 제약이 심하고 토큰을 발급한 계정의 정보만 가져올 수 있다는 단점

일전에 PHP snoopy 라이브러리로 썼는데 

자바 크롤링 검색 하니 주로 검색되는 키워드들이 셀레니움과 jsoup

크롬 플러그인을 사용한 셀레니움은 사용하고 싶지 않았고 그래서 선택한 라이브러리가 jsoup

기본적인 기능은 snoopy와 거의 비슷했다.

리퍼러 설정하고 쿠키 설정하고 agent 설정하고..등등등

 

여기까지는 순탄 했으나.. 인스타 그램은(?) 보안때문인건지 아니면 컨텐츠를 중요하게 생각하는건지

일단 인스타그램 페이지를 호출 하면 얘네들은 본페이지가 있고 이 페이지에서 컨텐츠를 재요청한다음

json으로 응답하고 리턴받은 json을 파싱해서 다시 html을 만들고 페이지를 로딩하고..

아 짜증났다.. 페이지 열어서 값 하나하나 찾아보다 지쳐서 

깃헙에 문의하고 스택오버플로 뒤지고 구글에 뒤지고 해서 찾았다.

js로 인스타 크롤링하는 플젝..ㅎㅎ

 

하지만 내가 하고 싶은건 java

js로 된 라이브러리에서 규칙 확인하고 자바로 컨버전 언어에 대한 이해가 있다면 아래 소스를 충분히 이해하고 가져다 

쓰실수 있을거라 보고 통으로 올린다.

 

테스트 하기 쉽게 java main 메소드로 올림

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.DataNode;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
 
public class crawlTest {
 
    public static void main(String[] args) {
        String url ="https://www.instagram.com/thesy88/";  //인스타그램 url
        String userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36";
        System.setProperty("sun.net.http.allowRestrictedHeaders""false");
//        String url = "https://www.instagram.com/p/CFS-pm3j3JK/";
        try {
            Connection.Response nvDocument = Jsoup.connect(url).userAgent(userAgent)
                    .method(Connection.Method.GET)
                    .execute();
 
            Document doc = nvDocument.parse();
 
            Elements datas = doc.select("script");
 
            for (Element data : datas) {
                for (DataNode node : data.dataNodes()) {
                    if (node.getWholeData().contains("window._sharedData =")) {
 
                        String nodeData = node.getWholeData();
 
                        nodeData = nodeData.replace("window._sharedData = """);
                        nodeData = nodeData.replace(nodeData.substring(nodeData.length() - 1), "");
 
                        JSONParser parser = new JSONParser();
                        JSONObject instaObj = (JSONObject) parser.parse(nodeData);
 
                        JSONObject entry_data = (JSONObject) instaObj.get("entry_data");
                        JSONArray profilePage = (JSONArray) entry_data.get("ProfilePage");
                        JSONObject profileData = (JSONObject) profilePage.get(0);
                        JSONObject graphql = (JSONObject) profileData.get("graphql");
                        JSONObject user2 = (JSONObject) graphql.get("user");
                        String biography = (String) user2.get("biography");
                        String proFileImg = (String) user2.get("profile_pic_url");
                        System.out.println("Biografia :" + biography);
                        System.out.println("proFileImg :" + proFileImg);
 
 
                        JSONObject edge_followed_by = (JSONObject) user2.get("edge_followed_by");
 
                        Long count = (Long) edge_followed_by.get("count");
                        System.out.println("follow --->:" + Long.toString(count));
 
                        JSONObject edge_follow = (JSONObject) user2.get("edge_follow");
                        Long count_edge_follow = (Long) edge_follow.get("count");
                        System.out.println("follower --->:" + Long.toString(count_edge_follow));
 
                        JSONObject edge_owner_to_timeline_media = (JSONObject) user2.get("edge_owner_to_timeline_media");
                        Long count_edge_owner_to_timeline_media = (Long) edge_owner_to_timeline_media.get("count");
                        System.out.println("게시물수 --->:" + Long.toString(count_edge_owner_to_timeline_media));
 
                        JSONArray edges = (JSONArray) edge_owner_to_timeline_media.get("edges");
 
                        edges.forEach(item -> {
                            JSONObject edge = (JSONObject) item;
                            JSONObject edgeNode = (JSONObject) edge.get("node");
                            String __typename = (String) edgeNode.get("__typename");
                            System.out.println("게시물 타입 --->:" + __typename);
 
                            String contents = "";
                            String contentsUrl = "";
 
                            if (__typename.equals("GraphVideo")) {
                                contents = (String) edgeNode.get("thumbnail_src");
                                System.out.println("이미지 URL --->:" + contents);
                            } else {
                                JSONArray contentsArray = (JSONArray) edgeNode.get("thumbnail_resources");
                                JSONObject contentsImg = (JSONObject) contentsArray.get(3);
                                contentsUrl = (String) contentsImg.get("src");
                                System.out.println("이미지 URL --->:" + contentsUrl);
                            }
 
                            JSONObject postLike = (JSONObject) edgeNode.get("edge_liked_by");
                            Long postLikeCnt = (Long) postLike.get("count");
 
                            System.out.println("좋아요 Count --->:" + postLikeCnt);
 
                            String postUrl = "https://www.instagram.com/p/" + (String) edgeNode.get("shortcode");
                            System.out.println("post 링크 --->:" + postUrl);
 
 
                            JSONObject contentsTextObj = (JSONObject) edgeNode.get("edge_media_to_caption");
                            JSONArray contextsTextArr = (JSONArray) contentsTextObj.get("edges");
                            if (contextsTextArr.size() > 0) {
                                JSONObject contentsTxtNode = (JSONObject) contextsTextArr.get(0);
                                contentsTxtNode = (JSONObject) contentsTxtNode.get("node");
                                String contentsStr = (String) contentsTxtNode.get("text");
 
                                System.out.println("내용 --->:" + contentsStr);
                            }
 
                        });
                        break;
                    }
                }
            }
        }catch (Exception e){
            System.out.println(e.toString());
        }
 
    }
}
 
cs

참고 했던 인스타그램 jquery feed

 

https://github.com/jsanahuja/InstagramFeed

 

단점.. 이유를 모르겠으나 특정 대역대에서 인스타그램 접근시 로그인 페이지로 redirect 시키는 경우가 있는데

이럴때는 크롤링이 안된다.

 

그래서 로그인 처리를 해보려고 했으나.. 이자식들 로그인도 엄청 어려워 패스워드를 비동기로 암호화해서 셋팅하고 또 그값을 다시 넘겨서 로그인 처리를 하는데.. csrToken값으로도 안되고.. 

 

언젠가는 다시 시도해보겠지만.. 일단 지금은 포기

 

다음편은 네이버, 유투브 정보도 올려야지!