# 파이썬 웹 크롤링

안녕하세요 코드사기꾼입니다.

오늘은 파이썬 urllib을 이용하여 웹상에서 사진을 가져오는 방법에대한 설명을 드리도록 하겠습니다.

 

 


1. 이미지 다운로드 하기

 

크롤링을 하기 전에 알아야 할것은 이미지가 웹상 특정 경로에 존재하는지에 관한 유무입니다. 저는 사진을 크롤링하기 위하여 네이버 영화의 마약왕 영화 리뷰 사이트를 참고하였습니다.

사이트 링크:

https://movie.naver.com/movie/bi/mi/basic.nhn?code=157297

 

마약왕

“애국이 별게 아니다! 일본에 뽕 팔믄 그게 바로 애국인기라!”마약도 수출하면 애국이 되던 1970년대 ...

movie.naver.com

 

사이트에 접속하시면 보이는 바와 같이 사진이 노출되는데요

 

 

왼쪽상단 빨간색 박스에 사진이 존재함

 

개발자 도구를 통하여 저 사진의 URL을 알아보도록 하겠습니다. 먼저 inspect 도구를 켜서 사진을 클릭해줍니다.

 

img 태그에 src에 사진의 url이 담겨있다.

 

그러면 사진과 같이 img태그안에 src 항목에 사진의 원본 url이 담겨있는것을 확인할 수 있습니다.

저 URL을 복사하시고 아래와 같은 소스 코드를 작성합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import urllib.request
from bs4 import BeautifulSoup
 
print('Beginning file download with urllib2...')
 
url = 'https://movie.naver.com/movie/bi/mi/basic.nhn?code=157297'
req = urllib.request.Request(url)
res = urllib.request.urlopen(url).read()
 
soup = BeautifulSoup(res,'html.parser')
soup = soup.find("div",class_="poster")
#img의 경로를 받아온다
imgUrl = soup.find("img")["src"]
 
#urlretrieve는 다운로드 함수
#img.alt는 이미지 대체 텍스트 == 마약왕
urllib.request.urlretrieve(imgUrl, soup.find("img")["alt"]+'.jpg')
cs

 

위 코드를 실행하면 실행된 스크립트가 있는 폴더에 아래와 같이 사진이 생성됩니다!

 


2. 실행 결과

 

사진이 스크립트가 실행된 경로에 저장되었습니다.

 

사진파일 실행 결과

 

사진이 좀 작네요 ㅋㅋㅋ 그래도 확실하게 이미지를 받아올 수 있었습니다.

# 파이썬 웹 크롤링

 

안녕하세요 코드사기꾼입니다.
저번 강의에 이어서 오늘은 다른 사이트를 크롤링해보는 시간을 갖도록 하겠습니다.

오늘의 대상 사이트는 각종 대회 및 공모전이 등록되는 사이트인 씽굿(ThinkGood)입니다. 항상 공모전은 하고 싶은데 매일 찾아보기는 귀찮잖아요? 하지만 공모전은 타이밍이라 자주 모니터링 하지 않으면 적절한 타이밍에 등록을 하지 못할 수도 있습니다. 공모전의 내용을 크롤링해서 띄워주는 프로그램이 있다면 굉장히 유요하게 쓰일 수 있겠죠?

 


 

1. 사이트 구조파악

크롤링을 하기에 앞서 가장먼저 선행되어야 할 것이 무엇이냐고 물어보면 저는 사이트 구조파악이라고 말할 것입니다.
사이트에 관한 구조를 모르면 원하는 url을 순환하면서 크롤링을 할 수 없을 뿐만 아니라 원하는 div에서원하는 콘텐츠를 크롤링해올 수 없기 때문이죠

씽굿에 접속해서 게임/소프트웨어 공모전으로 들어가 봅니다.
사이트 링크:
https://www.thinkcontest.com/Contest/CateField.html?c=12

 

씽굿-대한민국 대표 공모전 미디어 씽굿

부지런과 즐김 나의 삶의 철학은 부지런과 즐김이다. 부지런하고 즐기는 사람은 하늘도 못 말린다고 한다. ‘세 사람이 가면 그 중엔 반드시 나의 스승이 있다(三人行必有我師)’고 했는데, 나 또한 남의 좋은 점을 본받지 않고 스스로 잘난 척 옹고집으로 산 것을 심히 후회하노라. ‘아는 자는 좋아하는 자만 못하고, 좋아하는 자는 즐기는 자만 못하다(知者不如好者 好者不如樂者)’. 필자는 지금 이 나이에도 생물수필을 쓰고 있나니, 누가 시켜서라면 죽어도 안(못)할

www.thinkcontest.com

 


 

 

씽굿 접속 화면

오늘은 간단하게 크롤링 봇을 만들거라서 게임/소프트웨어 공모전 1페이지에 노출되어있는 공모전만 파싱하도록 하겠습니다. 공모전 분류별, 페이지별로 파싱해오고 링크 및 이미지를 파싱하는 방법에 대해서는 다음에 다시 업로드하도록하겠습니다.

 

 

 

개발자도구(f12)를 켜서 가장 첫번째 공모전의 태그를 확인하겠습니다. a태그로 감싸져 있는데요 이 div의 하위 태그로 구성되어 있는 것을 확인 할 수 있습니다. div클래스는 contest-title special이네요 그런데 special이라는 것은 special 아이콘이 붙은 공모전에만 들어가는 클래스이기 때문에 모든 공모전을 파싱하려면 저대로 파싱하면 아래와 같은 결과가 나옵니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import urllib.request
from bs4 import BeautifulSoup
 
 
url = "https://www.thinkcontest.com/Contest/CateField.html?c=12"
req = urllib.request.urlopen(url)
res = req.read()
 
soup = BeautifulSoup(res,'html.parser')
contests = soup.find_all("div",class_="contest-title special")
 
#a 함수는 html포맷데이터에서 a태그만을 파싱한다.
#a 함수를 쓰는 이유는 contests-title div가 다른 태그에 여러 텍스트를 가지고있기 때문이다.
#a를 제거하고 테스트해보는것을 추천드립니다.
keywords = [each_line.a.get_text().strip() for each_line in contests]
print(keywords)
 
cs

 

special 클래스의 공모전만 파싱됨

 

그러면 모든 공모전을 파싱하려면 어떻게 해야할까요? 일반적인 공모전이 담겨있는 div의 클래스명을 확인해보겠습니다.

 

일반 공모전

일반공모전은 contest-title이라고 되어있습니다. 그러면 클래스 이름에 contest-title이라고 적으면 될까요?

네 그것도 됩니다. 왜냐하면 BeautifulSoup은 정규표현식처럼 일정부분 맞게 들어가는 클래스명은 참이라고 판단하기 때문입니다.
하지만 오늘은 다른 방법을 알려드리고자 하기 때문에 새로운 방식으로 시도해보도록 하겠습니다.

먼저 정규표현식 라이브러리인 re를 import할것입니다. 그리고 정규식을 컴파일 하기위해 re.compile함수를 사용하겠습니다. 그러면 정규표현식은 어떻게 구성하면 될까요? contest-title을 포함하고 뒤에 스페셜을 있어도 되고 없어도 된다고 명시하면 될 것 같습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import urllib.request
import re
from bs4 import BeautifulSoup
 
url = "https://www.thinkcontest.com/Contest/CateField.html?c=12"
req = urllib.request.urlopen(url)
res = req.read()
 
soup = BeautifulSoup(res,'html.parser')
#regex: .*(문자의 유형과 상관없이 그것이 반복되면 매칭), ?(그것이 있을 수도 없을 수도 있음)
#.*?(그것은 문자의 반복이지만 있을 수도 없을 수도 있음)
#re.DOTALL == .이 개행문자를 포함한 모든문자를 의미하게함
contests = soup.find_all("div",class_=re.compile("contest-title.*?",re.DOTALL))
keywords = [each_line.a.get_text().strip() for each_line in contests]
print(keywords)
cs

 

최종 결과

 

# 파이썬 웹 크롤링


안녕하세요 코드사기꾼입니다.

오늘부터 웹 크롤링을 주제로 글을 작성해보도록 하겠습니다.

그럼 먼저 개념에 대해서 알고 시작해야겠죠? 크롤링이란 무엇일까요?


크롤링(Crawling)은  사전적으로 기어다니는 것을 뜻합니다. IT쪽에서는 웹페이지를 순회하면서 정보를 수집하는 행위를 말합니다. 크롤링은 스크래핑(Scraping) 또는 데이터 긁기등 다양한 단어로 불리우고 있고, 원하시는 용어를 사용하시면 됩니다.


1. BeautifulSoup


BeautifulSoup는 우리의 크롤링을 도와줄 파이썬 오픈소스 라이브러리 입니다. 정규표현식을 사용해서 크롤링한 데이터(html, xml등)내에서 원하는 부분을 추출할 수 있도록 도와줍니다.


공식사이트 링크:

https://www.crummy.com/software/BeautifulSoup/bs4/doc/#the-keyword-arguments



2. BeautifulSoup 설치


이 글은 파이썬 3.x 버전으로 진행하도록 하겠습니다. pip이 설치되어 있다는 가정하에 커맨드라인 프롬프트(cmd)에 아래와 같이 입력합니다.


1
pip install bs4
c
s



3. HTTP Request/Response


먼저 데이터를 크롤링하기 위해서는 웹소켓을 이용하여 원하는 웹사이트에 연결요청을 진행하여야 합니다. 연결요청을 하면 그에 대한 응답으로 웹서버는 Response를 보내는데요 이 데이터는 일반적으로 html이나 json형식을 띄고 있습니다. 이렇게 받아온 html, json데이터를 Beautiful Soup로 파싱 하는것을 크롤링이라고 하는것 입니다.


웹소켓에 대한 대표적인 라이브러리로는 requests, urllib이 있으며 제 블로그에서 일전에 requests에 관한 글을 작성해 놓았던게 있기 때문에 이번에는 urllib으로 진행하도록 하겠습니다.

urllib은 파이썬 기본 라이브러리입니다. 파이썬 2.x버전에서는 urllib, urllib2로 나누어져 있었는데 이것이 3.x버전에 들어서면서 통합되고 코드가 개선되었습니다.


1
2
3
4
5
6
# urllib을 사용한 Request 보내기
import urllib.request
 
url = "http://www.naver.com/"
req = urllib.request.urlopen(url) # url에 대한 연결요청
res = req.read() # 연결요청에 대한 응답
cs







4. 데이터 크롤링


지금 부터 본격적으로 데이터를 크롤링 해보도록 하겠습니다.

아까 설치한 bs4를 코드 최상단에 import하고 response로 받아온 html파일을 태그(tag)기준으로 크롤링 하겠습니다.

네이버 인기검색어를 크롤링 하도록 할텐데 먼저 어떤 태그안에 인기검색어가 저장되어있는지, 또 그 태그는 어떤 클래스로 정의되어 있는지를 파악해야 합니다. 그러기 위하여 크롬(Chrome)브라우저의 개발자도구를 이용하도록 하겠습니다.(f12를 누르면 개발자도구에 진입합니다.)




인기급상승 검색어는 sapn태그에 ah_k클래스를 사용하고 있다는 것을 확인하였습니다. 그러면 본격적으로 소스코드를 작성해 보겠습니다.(2번째 사진에서 빨간색 박스부분을 클릭한 후 원하는 곳을 클릭하면 해당 태그를 찾아줍니다. )


1
2
3
4
5
6
7
8
9
10
import urllib.request
from bs4 import BeautifulSoup
 
url = "https://www.naver.com/"
req = urllib.request.urlopen(url)
res = req.read()
 
soup = BeautifulSoup(res,'html.parser'# BeautifulSoup 객체생성
keywords = soup.find_all('span',class_='ah_k'# 데이터에서 태그와 클래스를 찾는 함수
print(keywords)
cs




크롤링해온 데이터는 html 태그에 쌓여진 리스트 형태로 리턴된다는 것을 알았습니다. 이번에는 코드에 함수하나를 추가해서 각 태그의 텍스트만 뽑아오도록 변경해 보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import urllib.request
from bs4 import BeautifulSoup
 
#여기에 함수를 구현해봅시다.
url = "https://www.naver.com/"
req = urllib.request.urlopen(url)
res = req.read()
 
soup = BeautifulSoup(res,'html.parser')
keywords = soup.find_all('span',class_='ah_k')
#get_text() == 데이터에서 문자열만 추출
#strip() == 데이터의 양옆 공백제거
#[:20]의 이유? 인기검색어의 중복을 막고 20위까지만 출력하기 위함
keywords = [each_line.get_text().strip() for each_line in keywords[:20]]
print(keywords)
cs



결과를 보시면 깔끔하게 검색어가 뽑혀있는것을 확인할 수 있습니다.

+ Recent posts