크롤링(crawling)
Pycharm 설정
pycharm 터미널에서 pyenv 환경 설정
# 커맨드 창 단축키 : alt + F12
# 사이드바 닫기/열기 :cmd + 1
# 터미널에서 pyenv version을 입력해 가상환경이 적용된 터미널인지 확인
# 안될 경우, .zshrc 파일에서 path 설정
$ vi ~/.zshrc
# Preferences > Build, Excution, Deployment > Console > Python Console > Python interpreter : Python 3.4.3 virtualenv
shell에서 Pycharm 어플리케이션을 열수있게 alias 추가
# 어플 이름과 경로 확인
$ cd /Applications
$ cd /PyCharm\ CE.app
$ vi ~/.zshrc
# alias 추가
alias py="open -a /Applications/PyCharm\ CE.app/Contents/MacOS/pycharm"
# py. 입력하여 pycharm 실행
웹 크롤링을 위한 라이브러리 설치
# beautifulsoup 설치
$ pip install beautifulsoup4
# requests 설치
$ pip install requests
# lxml 설치
$ pip install lxml
프로젝트 Interpreter 설정
Preferences > project: crawling > Project Interpreter > show all > add local > 경로: /usr/loca/var/pyenv/versions/fc-python/bin/python
네이버 웹툰 페이지 크롤링
참고 사이트
Request library
Requests 모듈을 import하여 웹 페이지를 가져온다.
import requests
r = requests.get('http://comic.naver.com/webtoon/list.nhn?titleId=690502')
print(r)
# result
$ python crawl.py
<Response [200]>
url 파라미터를 딕셔너리 타입으로 넣어 웹 페이지 가져온다.
import requests
url = 'http://comic.naver.com/webtoon/list.nhn'
params = {'titleId': '690502'}
r = requests.get(url, params=params)
print(r)
print(r.url)
$ python crawl.py
<Response [200]>
http://comic.naver.com/webtoon/list.nhn?titleId=690502
파라미터 1개의 key에 두개의 value를 받을 때, 리스트를 사용한다.
# request 문서
>>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']}
>>> r = requests.get('http://httpbin.org/get', params=payload)
>>> print(r.url)
http://httpbin.org/get?key1=value1&key2=value2&key2=value3
Beautiful Soup library
import requests
from bs4 import BeautifulSoup
# 네이버 웹툰 주소
url = 'http://comic.naver.com/webtoon/list.nhn'
# GET parameters로 전달한 값들의 dict
params = {'titleId': '690502'}
# requests.get 요청한 결과(response 객체)를 r변수에 할당
r = requests.get(url, params=params)
# response 객체(r)에서 text 메소드를 사용해 내용을 html_doc변수에 할당
html_doc = r.text
print(type(html_doc))
# BeautifulSoup 객체를 생성
soup = BeautifulSoup(html_doc, 'lxml')
# soup = BeautifulSoup(html_doc, 'html')
# print(soup.prettify())
# print(soup.title)
# print(soup.title.name)
# print(soup.title.string)
# 모든 a 태그 반환
# find_all : 요소 찾기
# a_list = print(soup.find_all('a'))
#
# for a in a_list:
# # print(a)
# print(a.get('href'))
# 제목만 가져오기
# td_list = soup.find_all('td', class_='title')
# for td in td_list:
# # print(td.get_text())
# # 공백제거를 위해 strip() 사용
# print('{}'.format(td.get_text().strip()))
1. 코드 분리
# 패키지 생성
# __init__.py 파일이 있으면 패키지
craling > new > python package > __init__.py 파일 자동생성
# 프로젝트 제일 상위 폴더를 source로 변경
crawling > mark directory as > Sources root
2. 단축키
# 코드 folding 단추키 : shift + cmd + +/-
Refactor > Rename : shift + F6
3. 정규 표현식
import re
# . : 임의 문자 아무거나
# * : 앞의 패턴이 0에서 무한대까지 반복
# no= : 찾을 문자(직전에서 멈춤)
# \d : 숫자
# \d+ : 1회 이상의 \d
# () : 그룹으로 지정
# [?&] : ? or &
# 아무 문자열이나 반복하다 ?no= 또는 &no= 이후의 숫자와
p = re.compile(r'.*[?&]no=(\d+).*')
# href와 p를 비교함
m = re.match(p, href)
# 링크주소에서 정규표현식의 패턴이 매치되었을 때
if m:
# 매치된 숫자를 recent_episode_number에 할당하고 반복문 종료
recent_episode_number = m.group(1)
break
모듈과 패키지
모듈
파이썬 파일 하나가 하나의 모듈로 취급한다. (모듈 단위로 클로저를 가짐 > 전역 변수 환경)
# shop.py
def buy_item():
print('Buy item!')
buy_item()
# game.py
def play_game():
print('Play game!')
play_game()
# lol.py
import game
import shop
print('= Turn on game =')
game.play_game()
shop.buy_item()
__name__변수
game
과 shop
이 import되는 순간 해당 코드가 실행되어 버리는 문제가 있다.
각 모듈은 자신의 이름을 가지며, 모듈 이름은 모듈의 전역변수 __name__
에서 확인 할 수 있다. 파이썬 인터프리터가 실행한 모듈의 경우, __main__
이라는 이름을 가진다. 따라서 아래와 같이 처리해준다.
# shop.py
def buy_item():
print('Buy item!')
if __name__ == '__main__':
buy_item()
네임스페이스 (Namespace)
각 모듈은 독립된 네임스페이스(이름공간)를 가진다. 메인으로 사용되고 있는 모듈이 아닌 import된 모듈의 경우, 해당 모듈의 네임스페이스를 사용해 모듈 내부의 데이터에 접근한다.
from을 사용해 모듈의 함수를 직접 import
import 모듈명
의 경우, 모듈의 이름이 전역 네임스페이스에 등록되어 모듈명.함수
로 사용가능하다.
모듈명을 생략하고 모듈 내부의 함수를 쓰고 싶다면, from 모듈명 import 함수명
으로 불러들일 수 있다.
from 모듈명 * 을 사용해 모듈 내 모든 식별자 (변수, 함수) import
from 모듈명 import
또는 import 모듈명
에서, 같은 모듈명이 존재하거나 혼동 될 수 있을 경우, 뒤에 as
를 붙여 사용할 모듈명을 변경할 수 있다.
패키지
패키지는 모듈들을 모아 둔 특별한 폴더를 뜻한다. (일반적인 폴더와는 다르다)
폴더를 패키지로 만들면 계층 구조를 가질 수 있으며, 모듈들을 해당 패키지에 모을 수 있는 역할을 한다.
패키지를 만들 때는 패키지로 사용할 폴더에 __init__.py
파일(패키지 초기화 파일)을 넣어주면, 해당 폴더는 패키지로 취급된다. (비어있어도 무관하다)
shop.py
와 game.py
를 func패키지에 넣어본다.
├── func
│ ├── __init__.py
│ ├── game.py
│ └── shop.py
└── lol.py
패키지는 모듈과 동일하게 import할 수 있다. 위와 같은 경우에는 from func import game, shop
으로 기존 코드의 변경 없이 패키지에서 모듈을 가져오는 방식을 사용할 수 있다.
또는 단순히 import func후 func.game, func.shop을 사용하는 방식도 가능하다.
*
, __all__
패키지에 포함된 하위 패키지 및 모듈을 불러올 때, *
을 사용하면 해당 모듈의 모든 식별자들을 불러온다.
이 때, 각 모듈에서 자신이 import될 때 불러와질 목록을 지정하고자 한다면 __all__
을 정의하면 된다.
# comment.py
__all__ = (
'Comment',
)
패키지 자체를 import시에 자동으로 가져오고 싶은 목록이 있다면, 패키지의 __init__.py
파일에 해당 항목을 import해주면 된다.
# __init__.py
from .comment import *
from .post import *
실습
- 위 프로그램에
friends
패키지를 만들고,send_message
함수를 가진chat
모듈을 추가한다.send_message
는input
을 이용해 2개의 인자를 받으며(친구명, 메세지), 실행 시print
함수를 통해 메세지를 보냈다는 문구를 출력한다. - 프로그램을 실행했을 때,
3
을 입력하면send_message
함수를 실행하도록 한다. - 커맨드라인으로 인자를 전달받아, 모두 더한 결과를 출력하는 모듈을 만든다. 이 때, 인터프리터를 통해 실행되었을 때만 결과가 출력되도록 한다.
- 위 3번의 프로그램에서, 정수형 데이터로 변환할 수없는 인자값이 올 경우 ‘올바른 값이 주어지지 않았습니다’ 를 출력하며 종료되도록 프로그램을 리펙토링해본다. 내장함수 isintance를 사용한다.