본문으로 바로가기

 

모듈 설치

요청 및 응답 등의 통신을 위한 requests 모듈을 설치합니다.

pip install requests

(crawling_blog) PS C:\Users\Desktop\pyqt\Example\begin_for_blog\2> pip install requests
Collecting requests
  Using cached requests-2.24.0-py2.py3-none-any.whl (61 kB)
Collecting idna<3,>=2.5
  Using cached idna-2.10-py2.py3-none-any.whl (58 kB)
Collecting chardet<4,>=3.0.2
  Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB)
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1
  Using cached urllib3-1.25.9-py2.py3-none-any.whl (126 kB)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\.conda\envs\crawling_blog\lib\site-packages (from requests) (2020.6.20)
Installing collected packages: idna, chardet, urllib3, requests
Successfully installed chardet-3.0.4 idna-2.10 requests-2.24.0 urllib3-1.25.9

 

parsing 하여 tag 를 잡을 수 있게 해주는 BeautifulSoup 모듈을 설치합니다.

(crawling_blog) PS C:\Users\Desktop\pyqt\Example\begin_for_blog\2> pip install bs4
Processing c:\users\appdata\local\pip\cache\wheels\a0\b0\b2\4f80b9456b87abedbc0bf2d52235414c3467d8889be38dd472\bs4-0.0.1-cp36-none-any.whl
Collecting beautifulsoup4
  Using cached beautifulsoup4-4.9.1-py3-none-any.whl (115 kB)
Collecting soupsieve>1.2
  Using cached soupsieve-2.0.1-py3-none-any.whl (32 kB)
Installing collected packages: soupsieve, beautifulsoup4, bs4
Successfully installed beautifulsoup4-4.9.1 bs4-0.0.1 soupsieve-2.0.1

 

코드

크롤러 클래스의 전체 코드입니다.

import requests
from bs4 import BeautifulSoup as bs

class GoogleWeather():
    url = 'https://www.google.com/search?q={}&rlz=1C1EJFA_enKR770KR770&oq=%EC%86%A1%ED%8C%8C%EA%B5%AC+%EB%82%A0%EC%94%A8&aqs=chrome..69i57.2835j0j8&sourceid=chrome&ie=UTF-8'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
    }
    result = []
    def __init__(self, keyword=None):
        self.keyword = keyword

    def set_keyword(self, keyword):
        self.keyword = keyword
    
    def run(self):
        res = requests.get(self.url.format(self.keyword), headers=self.headers)
        self.parse_html(res.text)
        return res

    def parse_html(self, text):
        html = bs(text, 'html.parser')
        loc = html.find('div', {'id': 'wob_loc'})
        loc = loc.string if loc else loc
        time = html.find('div', {'id': 'wob_dts'})
        time = time.string if time else time
        status = html.find('span', {'id': 'wob_dc'})
        status = status.string if status else status
        self.result.append({
            'loc': loc,
            'time': time,
            'status': status
        })

    def get_result(self):
        if self.result:
            return self.result[-1]
        else:
            return None

if __name__ == '__main__':
    crawler = GoogleWeather()
    while True:
        k = input('지역명 >> ')
        crawler.set_keyword(k + ' 날씨')
        crawler.run()
        r = crawler.get_result()
        for v in r.values(): print(v)
        print('-'*50)

 

개발자 도구를 열어서 이것 저것 확인을 해야합니다.

 

개발자 도구(F12) - Network - F15

 

통신방식(GET / POST)을 확인합니다.

GET 입니다.

res = requests.get(self.url.format(self.keyword), headers=self.headers)

 

Queary String Parameters 에는 요청시 파라미터들이 나와있고, 이 파라미터들을 url에 붙여서 요청하게 됩니다.

(지금은 '날씨' 와 기타 등등.)

 

requests.get(url, headers, params=params) 이러한 방식도 있습니다.

여기서는 쉽게 할 수 있는 방법을 소개합니다.

 

검색한 결과의 URL을 가져옵니다.

 

개발자 도구에 보면 다음과 같이 q 라는 파라미터에 키워드가 들어가는 것을 확인할 수 있습니다.

 

이렇게 하면 되겠죠. 

마지막에 요청시에만 keyword를 저장한 변수로 문자열을 완성합니다.

url = 'https://www.google.com/search?q={}&rlz=1C1EJFA_enKR770KR770&oq=%EC%86%A1%ED%8C%8C%EA%B5%AC+%EB%82%A0%EC%94%A8&aqs=chrome..69i57.2835j0j8&sourceid=chrome&ie=UTF-8'

...

res = requests.get(self.url.format(self.keyword), headers=self.headers)

 

또한, 구글 검색은 headers의 user-agent 가 포함되야합니다.

Requests Headers 가 내가 요청시에 보낸 Headers 입니다.

그 안에 user-agent를 복사해서 가져옵니다.

 

코드로는 다음과 같겠습니다.

headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
    }

...

res = requests.get(self.url.format(self.keyword), headers=self.headers)

 

이렇게 받은 응답을 보면 200 정상적인 응답이라고 합니다.

다만, 200이라고 안의 컨텐츠들이 내가 원하는 컨텐츠라고 장담할 수는 없습니다.

(예를들어, 자동 로그인을 만드는데 정상 응답에 컨텐츠가 '잘못된 패스워드입니다' 일 수도 있습니다.)

if __name__ == '__main__':
    crawler = GoogleWeather()
    crawler.set_keyword('송파구 날씨')
    r = crawler.run()
    print(r)
    print(type(r.text))
<Response [200]>
<class 'str'>

 

정상적으로 요청과 응답을 받았으면, 이제 내가 원하는 정보를 잡아야겠죠.

BeautifulSoup 을 이용해서 parsing 을 하면 태그를 잡을 수 있습니다.

def run(self):
    res = requests.get(self.url.format(self.keyword), headers=self.headers)
    self.parse_html(res.text)
    return res

def parse_html(self, text):
    html = bs(text, 'html.parser')
    loc = html.find('div', {'id': 'wob_loc'})
    loc = loc.string if loc else loc
    time = html.find('div', {'id': 'wob_dts'})
    time = time.string if time else time
    status = html.find('span', {'id': 'wob_dc'})
    status = status.string if status else status
    self.result.append({
        'loc': loc,
        'time': time,
        'status': status
    })

 

원하는 정보에 우클릭하고 요소 보기를 하면 다음과 같이 태그, 속성들이 보입니다.

class, id 두 개다 사용할 수 있겠습니다.

보통 id 가 유일하게 식별될 확률이 높습니다.

 

다음 코드를 통해 해당 태그를 잡을 수 있고

loc = html.find('div', {'id': 'wob_loc'})

그 태그에서 text 만을 추출합니다. (비슷한 함수들이 있고 차이점도 존재합니다.)

loc.get_text()

loc.Text()

loc.string

 

에러가 발생하지 않도록, 태그에 접근이 가능할 때만 text를 추출할 수 있도록 처리합니다.

(태그가 접근이 불가하면 None을 반환)

loc = html.find('div', {'id': 'wob_loc'})
loc = loc.string if loc else loc

 

 

활용

이렇게 모듈화한 크롤러는 제가 주로 다루고 있는 파이큐티(PyQt5), 텔레그램 봇 으로도 활용이 쉬워집니다.

 

 

파이큐티(PyQt5) 시작하기 - 구글 날씨 검색기 만들기 -1 : 디자이너 활용

디자인하기 먼저 MainWindow 를 하나 생성합니다. 키워드를 검색할 수 있는 입력창과 버튼 그리고 결과를 출력해줄 수 있는 위젯이 필요하겠습니다. QLineEdit, QPushButton, QTableWidget 을 배치하겠습니다.

jvvp.tistory.com

 

파이썬 파이큐티( PyQt5) 앱 만들기 : 이미지 다운로더(크롤러)

Image-Downloader 프로그램 시연 소개 및 기능 Imager-Downloader 앱은 키워드를 검색하여 크롤러를 통해 해당 이미지를 다운로드 합니다. 다운로드 받을 이미지 개수를 설정할 수 있으며 파일, 폴더, URL ��

jvvp.tistory.com