ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ Python ] 홈페이지에서 원하는 정보 가져오기 - 크롤링 초급편
    개발 언어/Python 2021. 11. 14. 02:20

    로그인하지 않고 웹에서 원하는 정보를 가져온다는 건 어떤 의미일까? 

    원하는 홈페이지와 통신을 하려면 HTTP을 알아야 한다. 

    웹 서버와 통신하려면 결국 내가 뭔가를 물어보고, 답을 받아와야 하는 단계를 거쳐야하는데 이를 'Resquest'와 'Response'라고 한 단다. 

     

    Request(물음) / Reponse(답)

     

    하지만 여기서 중요한 건 웹 서버가 원하는 방법대로 물어봐야 한다. 즉, 어느정도의 구조가 있다는 것.

    말로는 참 간단하지만 비전공자인 나에게 이런 저런 예제를 보면 참 복잡하기만 하다.

    우리는 HTTP의 구조나 역사를 공부할 시간이 없다. 그래서 간단히 정리를 했다.

     

    먼저 웹 크롤링을 하려면 내가 생각하는 단계는 이렇다. 

    1. 내가 원하는 정보는 무엇인가를 생각한다
    2. 내가 원하는 정보를 Chrome 분석도구를 통해 찾는다.
    3. Http구조를 알아와서 서버와 통신할 때 문법을 긁어온 후 크롤링 문법에 넣는다.
    4. 원하는 정보를 C#이나 Python에서 받아와서 Json에서 파싱한다.
    5. 끝.

     

    자 그럼 어떻게 하는지 알아보자. 

    Chrome 웹 페이지에서 웹페이지를 열고 Ctrl+F12를 눌러보면 이런 창을 볼 수 있다. 

    여기서 Network탭에서 Ctrl+R 혹은 Command+R을 눌러보자. 

    내가 원하는 정보는 아래 사이트에서 Trending 순위이다. 

    https://coinmarketcap.com/

     

    Cryptocurrency Prices, Charts And Market Capitalizations | CoinMarketCap

    Top cryptocurrency prices and charts, listed by market capitalization. Free access to current and historic data for Bitcoin and thousands of altcoins.

    coinmarketcap.com

     

    Chrome 검사 도구를 통해 원하는 파일이름을 클릭한다. 거의 모든 데이터는 Json파일 형식으로 data에 들어 있는 경우가 90%이상이다. 아래 순서와 같이 진행한다. 

     

    1. F12를 눌러 Chrome 검사 도구를 연다. 

    2. Network탭을 눌른다.

    3. Ctrl + R키를 누른다. 

    4. Name탭에서 원하는 정보가 어디 들어있는지 찾는다(Name 바로 옆 탭에 보면 Preview탭을 클릭하면 파일에 해당하는 파일내용을 미리 볼 수 있다)

    5. Preview탭을 참조해 Rank가 있는지 확인

    6. 확인했으면 Preview탭에서 Headers탭으로 이동

     

     

    그 다음은 Headers탭에서 이 파일이 웹 서버와 어떤 통신을 주고 받았는지 내용을 볼 수 있다. 

     

    여기서 중요하게 봐야 하는 부분은 General과 Request Headers이다. 

     

    Request 방식이 GET일때는 단순히 Server와 통신하는 방식이고, POST방식이면 우리가 Server에 자료를 요청할 때 좀 더 복잡한 Data형식으로 요청하는 방식이다. 지금은 간단히 GET방식으로 진행해 보자. 

    이렇게 Requests 방식으로 웹에 요청하는 방식이 왜 필요할까? 

    • 첫째. 내가 여러 웹사이트에서 로그인하지 않고 정보를 긇어올 수 있다(최초 한번만 로그인)
    • 둘째. 웹페이지를 여러 단계로 들어가지 않고 많은 데이터를 가져올 수 있다. 
    • 셋째. 매번 웹을 열어서 HTML을 긁어오는 방식은 동적으로 웹이 바뀌는 방식에서 수시로 데이터를 긁어오기 힘들다(스크롤 안에 데이터가 숨어 있는경우)

     

    여기서는 Python으로 크롤링을 진행해 보겠다. 

    우선 requests 패키지를 깔아 준다. 

    pip install requests

     

    이제 코딩을 통해 웹에 있는 정보를 가져올 것이다. 아까 Chrome검사 기능에서 Headers에서 우리는 WebServer에 어떻게 Request를 보낸지 알 수 있었다. 이 주소를 복사해 온다. https~~~~rank까지 복사함.

     

     

     

    이제 VisualCode로 넘어가서 코드로 작성해 보자.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import requests
    import json
     
    response=requests.get('https://api.coinmarketcap.com/data-api/v3/topsearch/rank').text
    print(response)
    cs

     

     

    requests.get().text 의 의미 

     

    requests(웹서버에 요청)하는데 get방식으로 ()안에 있는 주소에 있는 값을 text형식으로 주세요라고 하면 webserver에서

    요청하는 규칙에 맞는다면 text방식으로 값을 넘겨준다. 이때 규칙은 Headers값에 있는 값을 잘 지키면 된다.

    자 이 값을 print해보자. 

     

    엄청 복잡해 보이는 값이 나오는 걸 볼 수 있다. 복잡해 보이지만 잘 들여다 보면 간단하다.

    이 자료는 결국 아까 Chrome 검사 기능에서 본 Preview탭에서 본 자료랑 같은 것이다. Preview 탭에서 보면 훨씬 깔끔하다. 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {"data":{"exchangeTopSearchRanks":[],"cryptoTopSearchRanks":[{"id":12727,"dataType":2,"name":"Doge Dash","symbol":"DOGEDASH","slug":"doge-dash","rank":540,"status":"active","marketCap":65111071.18,
    "priceChange":{"price":0.001204714650556712529341,"priceChange24h":-23.09854621,"priceChange7d":-20.81956737,"priceChange30d":74.33407580,"volume24h":16867177.38320834}},{"id":13634,"dataType":2,
    "name":"SHIBORG INU","symbol":"SHIBORG","slug":"shiborg-inu","rank":3067,"status":"active","marketCap":0.00,"priceChange":{"price":4.484926998063750E-9,"priceChange24h":-34.66446939,
    "priceChange7d":-43.28175454,"priceChange30d":-82.02335674,"volume24h":2735780.20584766}},{"id":15427,"dataType":2,"name":"Rocket","symbol":"ROCKET","slug":"rocket",
    "rank":3034,"status":"active","marketCap":0.00,"priceChange":{"price":0.028437202196899966056694,"priceChange24h":-12.52100323,"priceChange7d":-42.95318014,"priceChange30d":-42.95318014,
    "volume24h":3257935.51448415}},{"id":14586,"dataType":2,"name":"ShibElon","symbol":"SHIBELON","slug":"shibelon","rank":3317,"status":"active","marketCap":0.00,"priceChange":
    {"price":0.000005027090033419331941,"priceChange24h":-12.62744518,"priceChange7d":-21.63409565,"priceChange30d":-11.76237666,"volume24h":1001683.88971850}},
    {"id":10165,"dataType":2,"name":"PORNROCKET","symbol":"PORNROCKET","slug":"pornrocket","rank":3254,"status":"active","marketCap":0.00,"priceChange":
    {"price":1.39326731546236251E-7,"priceChange24h":-13.14489793,"priceChange7d":-1.42518758,"priceChange30d":0.11844379,"volume24h":1190737.34995638}},
    {"id":14911,"dataType":2,"name":"MetaPets","symbol":"METAPETS","slug":"metapets","rank":3327,"status":"active","marketCap":0.00,"priceChange":
    {"price":1.11102331659950E-10,"priceChange24h":-22.78088673,"priceChange7d":-14.31996297,"priceChange30d":120.11468107,"volume24h":966630.46584280}},
    {"id":11541,"dataType":2,"name":"Ariva","symbol":"ARV","slug":"ariva","rank":790,"status":"active","marketCap":24851749.73,"priceChange":
    {"price":0.000486970778943199348744,"priceChange24h":-23.51171226,"priceChange7d":-20.13568369,"priceChange30d":-20.56630675,"volume24h":6446857.11461437}},
    {"id":12973,"dataType":2,"name":"MicroPets","symbol":"PETS","slug":"micropets","rank":925,"status":"active","marketCap":17344174.75,"priceChange":
    {"price":0.000003463902193805507990,"priceChange24h":-11.90305395,"priceChange7d":-18.61320176,"priceChange30d":-9.60975148,"volume24h":899194.86244837}},
    {"id":15263,"dataType":2,"name":"Shiba Metaverse","symbol":"SHIBMETA","slug":"shiba-metaverse","rank":3284,"status":"active","marketCap":0.00,"priceChange":
    {"price":0.008025002592328484496187,"priceChange24h":139.26775038,"priceChange7d":-46.45966558,"priceChange30d":-46.45966558,"volume24h":1090679.35097043}},{"id":14161,"dataType":2,"name":"1NFT","symbol":"1NFT","slug":"1nft","rank":2956,"status":"active","marketCap":0.00,"priceChange":{"price":7.06602096736616E-10,"priceChange24h":-14.64974423,"priceChange7d":-15.32669190,"priceChange30d":-73.58077657,"volume24h":5138219.19862098}}],"cryptoMostVisitedList":[]},"status":{"timestamp":"2021-12-04T14:00:59.612Z","error_code":"0","error_message":"SUCCESS","elapsed":"12","credit_count":0}}
    cs

     

    여기서 보면 가장 큰 {}는 data이고, 그 다음이 exchangeTopSearchRanks:[{id..}{id..}.....] 이렇게 계층으로 이루어져 있다.

    가장 높은 상위 이름은 

              data와 status이다. 그 다음 그 다음 그 다음... 우리가 여기서 필요한건 data이다. 

     

    또 위 데이터를 보면 Rank중 name안에 있는 이름이 다 필요하다. 그렇다면 data 안에 ['cryptoTopSearchRanks'][배열]['name'] 이 필요하다. 이런 자료를 파싱하려면 json패키지가 필요하다. 

    json 패키지를 설치한다. 

     

    pip install json

     

    JSON이란

     

    "데이터 이름" : 값

    으로 이루어진 객체이다. 여기서 각 속성은 쉼표(,)로 구분이 된다. 

    "직원"{
    "이름" : "홍길동",
    "나이" : 41
    }

     

    JSON의 배열 

    "팀A":[
    {"이름":"직원1","나이":32},
    {"이름":"직원2","나이":25},
    {"이름":"직원3","나이":21},
    {"이름":"직원4","나이":41}
    ]

     

    이 구조를 이해하고, Trending 데이터를 보면 이해가 빠를 것이다. 

    그리고 아래와 같이 코드를 적어준다. 

    1
    2
    3
    4
    5
    6
    import requests
    import json
     
    response=requests.get('https://api.coinmarketcap.com/data-api/v3/topsearch/rank').text
    jsonObject=json.loads(response)['data']
    print(jsonObject['cryptoTopSearchRanks'][0]['name'])
    cs

     

    json패키지의 문법은 ['프로퍼티 이름']['하위 프로퍼티 이름']이렇게 접근가능하다. 

    json에서 loads로 response에서 ['data']만 가져오려면 loads라는 명령어에 response를 넣고 data만 가져온다.  그러면 data아래 자료만 jsonObject에 저장된다. 

    거기서 아까 위에서 배운 JSON의 배열처럼  cryptoTopSearchRanks 는 []로 배열로 이루어져 있다. 그렇다면 [0]처럼 인덱스로 배열에 접근할 수 있을 것이다. 위와 같이 작성했다면 결과를 확인해 본다. 

     
     결과.
     
     
    1
    Doge Dash
    cs

    웹에서 보던 리스트와 동일하다. 그렇다면 전체 리스트를 가져 올 수 없을까? 배열을 0부터 9까지 돌면서 가져오면 될 것이다.

     

    전체 리스트 가져오기
     
     
     
    for i in range()사용하기 range(10)이면 0부터 9까지 인덱스를 i에 저장한다. 
    아래와 같이 코드를 작성해 보자. 
     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import requests
    import json
     
    response=requests.get('https://api.coinmarketcap.com/data-api/v3/topsearch/rank').text
    jsonObject=json.loads(response)['data']
     
    for i in range(10):
        print(jsonObject['cryptoTopSearchRanks'][i]['name'])
       
    cs

     

    여기서는 총 0부터 9개이니 10번을 돌면 될 것이다. range를 10으로 하면 0부터 9까지 배열을 돌면서 name을 프린트 해준다. 

    결과

    1
    Doge Dash
    cs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Doge Dash
    SHIBORG INU
    Rocket
    ShibElon
    PORNROCKET
    MetaPets
    Ariva
    MicroPets
    Shiba Metaverse
    1NFT
       
    cs

     

    이런 방법으로 내가 원하는 많은 홈페이지에서 데이터를 가져와서 가공해서 데이터를 보여주는 홈페이지를 만들 수 도 잇을 것이고, 앱에도 활용할 수 있을 것이다. 

    반응형

    댓글