Python
87일차 2023-07-11
choi Hoon
2023. 7. 11. 19:37
PYTHON
crawlling개념
1.개발환경 구축
1-1.Anaconda설치
-Anancon는 파이썬 배포판으로 레드햇에서 만들었으며 파이썬과 C언어로 만들어진 가장 인기 있는
파이썬 데이타 분석 오픈 플랫폼이다.
-https://www.anaconda.com/에서 ANACONDA.DISTRIBUTION다운로드
-https://docs.anaconda.com/anaconda/install/
※We recommend not adding Anaconda to the PATH environment variable,
since this can interfere with other software.
Instead, use Anaconda software by opening Anaconda Navigator or
the Anaconda Prompt from the Start Menu.
-conda 주요 명령어
:버전확인
conda --version
:conda 업데이트하기
conda update -n base conda
그리고 설치된 파이썬 패키지를 모두 최신 버전으로 업데이트
conda update --all
:도움말
--help
예]conda update --help
:파이썬 버전 확인
python --version
:가상환경 생성
conda create -n[ame] 가상환경명 설치할 패키지
예]conda create --n crawling python=3.5
(나는 이걸 실행함)C:\Users\kosmo\anaconda3\Scripts>conda create --name crawl python=3.10
※conda는 venv와는 달리 가상 환경을 현재 폴더에 생성하지 않고 아나콘다 설치 폴더의 envs 안에 생성
즉 C:\Users\컴퓨터명\Anaconda3\envs\crawling에 생긴다
:설치된 가상환경 목록 보기
conda info --envs
:가상환경 활성화 -리눅스를 사용시 명령어 앞에 source를 붙여줘야 한다.
activate 가상환경명
:가상환경 비활성화 -리눅스를 사용시 명령어 앞에 source를 붙여줘야 한다.
conda deactivate
:가상환경 삭제
conda remove -n 가상환경명 --all
:패키지 설치 관련 명령어
conda search 패키지: 패키지 검색
conda install 패키지=버전: 특정 버전의 패키지를 설치
conda update 패키지: 패키지 업데이트
conda list: 패키지 목록 출력
conda remove 패키지: 패키지 삭제
conda list --export > package-list.txt: 패키지 목록 및 버전 정보 저장:
conda install --file package-list.txt: 패키지 목록으로 설치
※아나콘다 설치된 경로
Just Me로 설치시 :C:\Users\컴퓨터명\Anaconda3
All Users로 설치시:C:\ProgramData\Anaconda3
※Jupyter Notebook(구 IPython Notebook) : 데이터 분석이나 과학용 프로그래밍을을 할때 매우 유용한 도구로
파이썬 전체 코드를 실행 시킬 필요 없이 한 라인씩 대화 형식으로
실행할 수 있는 대화형 IDE개발도구(웹 기반)
즉 코드를 노트북 단위로 관리 할 수 있는 도구이다
아나콘다의 디폴트 가상환경에는 이미 설치되어 있지만 새롭게 만든 가상환경에는 별도로 설치 해야 한다
(crawling) C:\Users\KSM06-00>conda install jupyter
실행시 (crawling) C:\Users\KSM06-00>jupyter notebook
1-2. PyCharm설치
- 가벼운 파이썬 IDE 개발도구
-https://www.jetbrains.com/pycharm/download/#section=windows에서
Community버전 다운로드
-프로젝트 생성하기
1.D:\CCH\Python\Workspace\Crawling디렉토리 생성
2.파이참 실행후 New Project시 Location을 1에서 설정한 디렉토리로 설정
Project Interpreter는 Ananconda 가상환경으로 설정하기 위해
Existing Interpreter 선택후 ...을 클릭해서
C:\Users\KSM06-00\Anaconda3\envs\crawling\python.exe선택
2. 웹 크롤링(Web Crawling)과 웹 스크레이핑(Web Scraping)
-웹 크롤링 :정해진 규칙에따라 특정 사이트나 여러 사이트를 정기적으로 돌며 브라우징 하는 기술
-웹 스크레이핑:웹 사이트에 있는 특정 정보를 추출하는 기술
3. 웹 크롤링 및 스크래핑을 위한 Python 주요 라이브러리
https://docs.python.org/ko/3/library/urllib.html
3-1. urllib : URL 작업을 위한 여러 모듈을 모아놓은 패키지로 웹상의 문서나 파일을 가져올 수 있다(표준 라이브러리)
urllib.request모듈- URL을 열고 읽기 위한 모듈
-urlretrieve()함수:웹 상의 문서를 다운로드하기 위한 함수
-urlopen(웹페이지 주소)함수:웹에서 얻은 데이타에 대한 객체를 반환
urlretrieve()함수와 달리 읽어 들인 데이타를
변수에 저장하여 처리가능하다
-getheaders():응답헤더에 대한 정보를 리스트로 반환
-status : 응답에 대한 상태 코드가 저장되어 있다
-read() : 웹에서 얻은 데이타를 반환(읽은 데이타는 바이너리 데이타)
-decode():read()함수로 읽은 웹 데이타를 문자열로 변환하기 위한 함수
urllib.parse모듈 -URL 구문 분석을 위한 모듈로 url에 한글이 포한된 경우
한글을 URL인코딩해주는 모듈
※URL에 사용할 수 있는 문자는 영문자, 숫자, 몇몇 기호 뿐이다.
그 밖의 문자(한글·한자·특수문자 등)는 사용할 수 없다.
urlopen()이나 urlretrieve()함수로 URL요청시 한글·한자·특수문자등이 포함되면 에러난다
이때는 URL인코딩 함수를 통해 인코딩해서 요청해야 한다
-quote(문자열) : URL 인코딩 함수(공백을 %20으로 인코딩)
-unquote():URL 디코딩 함수
-quote_plus(문자열):한글 URL인코딩 함수.(공백을 +로 그리고 :도 인코딩)
-unquote_plus(문자열):한글 URL디코딩 함수.
-urlsplit(주소):URL을 각 부분으로 나눠 튜플로 반환
-urlunsplit():나눈 URL을 합치는 함수
-urlencode(딕션너리형태의 인자):이름=값&이름2=값2&..의 형태로
딕션너리를 URL인코딩해서 반환
※urllib나 requests로 특정 웹페이지 스크래핑시
HTTP Error 403: Forbidden에러가 나는 경우
원인-비 정상적인 접근으로 보고 차단하는 경우임
해결책- 요청 헤더를 삽입
import urllib.request
headers = {'User-Agent': 'Mozilla/5.0'}
req = urllib.request.Request(요청주소, headers=headers)
data = urllib.request.urlopen(req).read().decode('utf-8')
print(data)
import requests
headers = {'User-Agent': 'Mozilla/5.0'}
res = requests.get('요청주소', headers=headers)
※urllib와 urlib2 그리고 requests모듈 비교
파이썬 2.x에서:
import urllib2
urllib2.urlopen("https://www.python.org").read()
Python 3.x:
import urllib.request
urllib.request.urlopen("https://www.python.org").read()
파이썬 2.x ,3.x 둘다 :
import requests
r = requests.get("https://www.python.org")
print(r.status_code)
print(r.headers)
print(r.content)
3-2.requests : Apache2 라이센스의 Apache2 라이센스의 HTTP 라이브러리로,
인간을 위한 HTTP(HTTP for Humans)라는 모토로 2014년 8월을 기준으로 2.3.0 버전까지 개발
되었다.
-GET, POST 등에서 사용하면 필요한 Request 인코딩을 자동으로 처리
-JSON디코더가 내장되어 있어 json.loads()와 같이 추가적으로 json모듈 불필요
http://docs.python-requests.org/en/latest/
1. 설치
(crawling) C:\Users\KSM06-00>conda install requests
혹은
파이참의 File-Settings-Project Interpreter에서 설치(※설치시 use conda package manager아이콘 선택)
get('웹페이지 주소',[,params=딕션너리타입][,headers=딕션너리타입][,cookies=딕션너리타입][timeout=초]): get방식으로 요청.특정 주소의 Response객체 반환
post('웹페이지 주소',[,data=딕션너리타입][,headers=딕션너리타입][,cookies=딕션너리타입][timeout=초]): post방식으로 요청.특정 주소의 Responst객체 반환
json():서버에서 json으로 응답보낼때 딕셔너리 타입으로 반환
raise_for_status():200 OK코드가 아닌 경우 에러 발생
text : Respons객체의 속성으로 HTML소스가 저장됨
headers: Respons객체의 속성으로 응답 헤더가 저장됨
status_code: Respons객체의 속성으로 상태 코드가 저장됨
request:Respons객체의 속성으로 내가 보낸 요청객체
※urllib3는 requests모듈 설치시 함께 설치된다.
urllib3는 응답을 바이너리로 한다
https://urllib3.readthedocs.io/en/latest/user-guide.html
3-3.BeautifulSoup :html이나 xml을 파싱할때 주로 많이 사용하는 외부 라이브러리.
https://www.crummy.com/software/BeautifulSoup/bs4/doc/
1.설치
pip install bs4혹은(bs4는 beautifulsoup4의 Wrapper 패키지다)
혹은
파이참의 File-Settings-Project Interpreter에서 설치(※설치시 use conda package manager아이콘 선택)
2.생성자
첫 인자는 html소스코드 혹은 파일객체, 두 번째 인자는 어떤 parser를 이용할지 명시(총 4가지 파서가능).
soup = BeautifulSoup(html, 'html.parser')
3.검색하기
-태그명으로 bs4.element.Tag객체 하나 가져오기:중복이면 가장 첫 번째 태그를 가져온다
없으면 None
soup.태그명
soup.find("태그명")
-태그명 가져오기
bs4.element.Tag객체.name
-태그가 감싸고 있는 텍스트 가져오기
bs4.element.Tag객체.string :텍스트가 없는 경우 None
bs4.element.Tag객체.text:텍스트가 없는 경우 ''
bs4.element.Tag객체.get_text():텍스트가 없는 경우 ''
-태그명으로 모든 태그 검색:반환값은 무조건 리스트.찾는 태그가 없으면 빈 리스트를 반환
soup.find_all("태그명")
soup.find_all(["태그명1","태그명2",...])
soup("태그명")
-태그명으로 특정 갯수만 가져오기
soup("태그명", limit=갯수)
soup.find_all("태그명", limit=갯수)
-텍스트에서 특정 문자열을 찾기:찾은 문자열을 리스트로 반환
soup.find_all(string="찾을 문자열")
soup.find_all(string=["찾을 문자열1","찾을 문자열2","찾을 문자열3",..])#OR검색
soup.find_all(string=re.compile("정규표현식"))#정규 표현식으로 패턴검색.
import re
-태그의 속성값 가져오기:첫번째로 나타나는 태그의 속성값을 가져옴
<h1 title="aaaaa'>
soup.태그명['속성명']
soup.태그명.get('속성명')
soup.태그명.attrs['속성명']
-id속성으로 찾기
soup.find(id="아이디명")
soup.find('',{'id':'아이디명'})
-class속성으로 찾기
soup.find_all(class_="클래스명")#class는 파이썬의 예약어 그래서 class_사용
soup.find_all('',{'class':'클래스명'})
-select('CSS셀렉터'): CSS Selector를 사용해 find_all()을 수행.
-select_one('CSS셀렉터'): CSS Selector를 사용해 find()을 수행.
※BeautifulSoup는 CSS셀렉터는 지원하나 XPATH는 지원하지 않는다
3-4. Selenium :웹 테스트 자동화 도구로 웹드라이버를 통해 브라우저를 제어해서
웹을 테스트하는 용도로 사용하는 라이브러리다.
자동화 웹 테스트를 위한 여러가지 기능을 제공한다
이 라이브라리를 사용하여 BeautifulSoup로
스크래핑이 안되는 동적 페이지나 로그인이 필요한 페이지등을 스크래핑 할 수 있다
http://selenium-python.readthedocs.org/api.html#locate-elements-by
1. 설치
(crawling) C:\Users\KSM06-00>conda install selenium
혹은
파이참의 File-Settings-Project Interpreter에서 설치(※설치시 use conda package manager아이콘 선택)
2. 웹 드라이버 다운로드:웹드라이버로 브라우저 제어
http://chromedriver.chromium.org/downloads
3. 브라우저 제어 테스트
from selenium import webdriver
driverpath='다운받은 드라이버 exe파일 경로'
driver = webdriver.Chrome(driverpath)#크롬 브라우저가 자동으로 실행됨
#특정 사이트 열기
driver.get('특정 사이트 주소')#크롬 브라우저에 특정 사이트가 보인다
#코드로 사이트의 버튼 클릭하기
driver.find_element_by_class_name('개발자도구로 찾아낸 클래스명').click()
#빠져 나가기
driver.quit()
4.WebDriver객체의 주요메소드
-URL에 접근:
get("특정 사이트 주소")
-페이지의 단일 요소 가져오기:<class 'selenium.webdriver.remote.webelement.WebElement'>반환
find_element_by_name("name속성값")
find_element_by_id("아이디 속성값")
find_element_by_xpath("xpath")
find_element_by_css_selector("CSS 셀렉터")
find_element_by_class_name("class명")
find_element_by_tag_name("태그명")
-페이지의 여러 요소 가져오기:파이썬 list객체 반환
find_elements_by_name("name속성값")
find_elements_by_xpath("xpath")
find_elements_by_css_selector("CSS 셀렉터")
find_elements_by_class_name("class명")
find_elements_by_tag_name("태그명")
-자바스크립트 실행
execute_script('자바스크립트 코드')
-브라우저 닫기
quit()
-HTML 소스 가져오기
page_source 속성
5.WebElement객체의 주요메소드
-find_element계열(s가 빠짐)로 찾는 곳에 값 보내기
※find_elements계열은 list를 반환함으로 send_keys()를 바로 적용할 수없다
인덱스로 접근해서 적용해야 한다
send_keys("보낼 값")
-태그의 속성으로 속성값 가져오기
get_attribute('태그의 속성명')
-찾은 요소를 클릭- 버튼에 적용한다
click()
-전송하는 메소드로 주로 폼 태그요소에 적용한다
submit()
-텍스트 가져오기
text속성
※ElementNotVisibleException에러
-기본적으로 웝드라이버는 페이지가 로드될때까지 기다린다 즉 웹브라우저에 완전히 로드되면
다음 코드가 진행된다 하지만 ajax요청이나 IFRAME내에 있는 내용을 요청하면 기다리지 않는다
즉 Ajax로 요청을 하는 경우 동적으로 HTML 구조가 변하기때문에
Ajax처리가 끝나지 않은 상태에서 사이트를 로딩한 직후에
동적으로 자바스크립트에 의해 생성되는 HTML 엘리먼트를 가져오려고 하는 경우 발생
-특정조건 혹은 지정한 시간동안 대기시키는 방법
1. Implicit Wait(암묵적 대기):지정한 초만큼 기다려주는 방식(기본값은 0초)
만약 요소를 찾는 코드를 실행시킬때 찾는 요소가 없다면
지정한 초후에는 Exception을 발생시킨다
-driver.implicitly_wait(초단위) :
웹드라버의 get()이나 find계열 함수로 HTML요소를 가져올때
각 HTML요소가 나타날때까지 브라우저를 최대 지정한 초만큼 기다리게 하는 함수
2. Explicit Wait(명시적 대기) :특정 HTML요소가 나타날때까지 기다려주는 방식
WebDriverWait의 until함수를 통해 설정한다
1. 아래 3개의 모듈을 IMPORT한다
#기대조건을 설정하기위함
from selenium.webdriver.support import expected_conditions as EC
#기대조건이 만족할때까지 기다리기위한 함수사용 용
from selenium.webdriver.support.ui import WebDriverWait
#위치 지정자용
from selenium.webdriver.common.by import By
2. EC로 기대 조건 설정
EC.presence_of_element_located((위치지정자,'위치 지정자에 따른 찾을 요소'))
위치 지정자는 아래와 같다:#https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions
By.ID - ID속성으로 로 검색
By.CLASS_NAME - CLASS속성으로 검색
By.CSS_SELECTOR - CSS Selector 로 검색
By.XPATH - XPATH로 검색
By.NAME - NAME속성으로 검색
By.TAG_NAME - 태그 이름으로 검색
※EC는 웹드라이버가 웹페이지의 특정요소를 로드할때까지 기대조건을 설정하기위한 객체이다
3. WebDriverWait클래스로 기대조건이 만족할때까지
최대 지정한 초만큼 기다린다
WebDriverWait 함수에서 지정한 초까지 대기해서 until에 전달된 내용이 참이 되지 않으면
TimeoutException이 발생.
그리고 지정한 초 이전에 until에 전달된 내용이 참이 되면 바로 다음 코드로 넘어간다.
WebDriverWait(웹드라이버객체,초단위).until(기대조건)
예]
#트위터에 자동 로그인하기
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
try:
# Wait as long as required, or maximum of 3 sec for element to appear
# If successful, retrieves the element
inputbox_user = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CLASS_NAME, "js-username-field")))
print(inputbox_user)
inputbox_user.send_keys('아이디') #아이디 타이핑을 위한 키이벤트 전송
inputbox_pass = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CLASS_NAME, "js-password-field")))
inputbox_pass.send_keys('비밀번호')#비번 타이핑을 위한 키이벤트 전송
inputbox_pass.send_keys(Keys.RETURN) # Enter키를 누르기
except TimeoutException:
print("해당 페이지에 태그 요소가 존재하지 않거나, 해당 페이지가 3초 안에 열리지 않음.")
finally:
#driver.quit()
pass
3-5. Scrapy :웹 사이트로부터 필요한 데이타를 추출하기 위한 파이썬으로 작성된 웹 크롤링 오픈 소스 프레임 워크이다
단,Ajax로 데이타를 불러오는 동적 웹 페이지나 로그인 정보를 함께 보내는 웹 페이지
등은 보고있는 화면을 그대로 스크래핑 할 수 없다.
https://scrapy.org/
※로봇 배제 표준:https://ko.wikipedia.org
:해당 사이트의 웹 크롤링 가능여부를 알아 볼 수 있는 표준으로
해당사이트 주소 뒤에 '/robots.txt'를 입력하면 크롤링 가능 여부를
확인 할 수 있다
1.라이브러리 설치:가상환경에서 설치하는 것을 권장
pip를 사용하여 Windows에 Scrapy를 설치할 수도 있지만, Anaconda 또는 Miniconda 를 설치 하고
conda-forge 채널 의 패키지를 사용하는 것이 좋다(대부분의 설치 문제가 발생하지 않음)
a. 아나콘다 설치
b. (crawling) C:\Users\KSM06-00>conda install -c conda-forge scrapy
2.Scrapy Shell:프로젝트를 생성하지 않고 간단하게 Scrapy를 체험할 수 있는 대화식 프로그램
# scrapy shell 실행
1.(crawling) C:\Users\KSM06-00>scrapy shell
>>fetch('http://news.naver.com')#크롤링을 시작할 위치를 설정
혹은
(crawling) C:\Users\KSM06-00>scrapy shell "http://news.naver.com"
#다운로드한 페이지 보기:크롤러가 다운로드한 페이지를 기본 브라우저를 통해 실행
#response는 크롤링시 요청한 사이트에 대한 응답 객체이다
2.>>>view(response)
#요청한 url
3.>>>print(response.url)
#HTML소스보기
4.>>>print(response.text)
#이시간 주요 뉴스 제목 스크래핑하기:크롬 개발자도구 활용해서 제목 부분 xpath복사
5.>>>titles=response.xpath('//*[@id="text_today_main_news_801001"]/li[1]/div/a/strong')#Selector객체가 저장된 list반환
6.>>>titles[0]#Selector객체
<Selector xpath='//*[@id="text_today_main_news_801001"]/li[1]/div/a/strong' data='<strong>출구 안 보이는 방위비분담금 협상…팽팽한 줄다리기</str'>
7.>>>titles[0].xpath('./text()')#xpath에서 Selector의 data부분의 텍스트만 가져올때는 text()
[<Selector xpath='./text()' data='출구 안 보이는 방위비분담금 협상…팽팽한 줄다리기'>]
8.>>>titles[0].xpath('./text()').extract()#Selector의 data추출시 extract()
['출구 안 보이는 방위비분담금 협상…팽팽한 줄다리기']
9.>>>titles[0].xpath('./text()').extract()[0]
혹은 >>>titles[0].xpath('./text()').extract_first()
'출구 안 보이는 방위비분담금 협상…팽팽한 줄다리기'
10.titles=response.xpath('//*[@id="text_today_main_news_801001"]/li/div/a/strong/text()').extract()
11.>>>for title in titles:
... print( title.strip())
#css selector로 스크래핑하기:css selector에서 Selector의 data부분의 텍스트만 가져올때는 가져올때는 ::text
12.>>>titles=response.css('#text_today_main_news_801001 > li > div > a > strong::text').extract()
13.>>>for title in titles:
14.>>> print( title.strip())
#exit()명령어로 나오기
15.>>>exit()
3. Scrapy 프로젝트 구조
가상환경에서 scrapy startproject 프로젝트명 명령어로
프로젝트 생성시 아래와 같이 구조가 생성된다
\프로젝트명
\프로젝트명
\spiders
__init__.py
items.py
middlewares.py
pipelines.py
settings.py
spiders폴더:Spider역할을 하는 클래스를 작성하는 폴더로 특정 웹 사이트들을 어떠한 규칙에 의거하여
크롤링할 것인지 그리고 웹 페이지의 어떤 부분을
스크래핑할 것인지 등을 설정하는 클래스를 작성하는 폴더이다(파일명은 임의로)
※스파이더란? 자동으로 하이퍼링크를 따라가거나 검색 엔진 검색을 위한 웹페이지를 색인화하는 프로그램
items.py:스크래핑할 데이터를 담을 자료구조 클래스를 정의하는 파일
pipelines.py:클래스를 작성하는 파일로
Spider에 의해 스크래핑된 아이템은 Item Pipeline으로 보내진다
Item Pipeline(클래스)은 받은 아이템을
어떻게 처리할 것인지 설정하는 파일로
설정한 규칙에 따라 데이터를 가공하거나
혹은 외부 파일로 간편하게 저장할 수 있다.
settings.py:spiders폴더안에 만든 Spider나 Item Pipeline 등의 세부적인 동작사항을 설정하는 파일
예]
Item Pipeline 활성화하기
ITEM_PIPELINES = {
'BOT이름(프로젝트명).pipelines.파이프라인클래스명': 300,
'BOT이름(프로젝트명).pipelines.파이프라인클래스명': 800,
}
여기서 숫자는 파이프라인의 실행 순서를 결정하는 것으로
값이 낮을 수록 먼저 실행된다.숫자는 0 ~1000사이의 값을 설정한다
※JSON형식의 데이타 파일로 처리
1. JSON은 JavaScript Object Notation의 약자로서
Lightweight한 데이타 표현 방식이다.
JSON은 데이타를 교환하는 한 포맷으로서 그 단순함과 유연함 때문에
널리 사용되고 있다. 특히 웹 브라우져와 웹서버 사이에 데이타를 교환하는데
많이 사용되고 있다.
Python은 기본적으로 JSON 표준 라이브러리(json)를 제공하고 있다(Python 2.6 이상).
2. 파이썬의 객체(Dictionary, List, Tuple 등)를 dumps()메소드를
통해 JSON 문자열로 변경할 수 있다(JSON 인코딩)
또한 JSON 문자열을 loads()메소드로 다시 파이썬 객체로
변환할 수 있다 (JSON 디코딩).
예제1]
import json
# 테스트용 Python Dictionary
member = {
'id': 'KIM',
'name': '김길동',
'age':20
}
# JSON 인코딩
js = json.dumps(member)
# 문자열 출력
print(js)
print(type(js)) # class str
js = json.dumps(member, indent=4)#indent키워드 인수 지정시 인덴트 적용된 JSON문자열 반환
#js = json.dumps(member, ensure_ascii=False)#json파일로 저장시 한글 인코딩 문제 해결을 위해 ensure_ascii=False인자 추가
print(js)
예제2]
#urllib.request.urlopen()함수로 JSON데이타 읽기
import urllib.request
import json
req = urllib.request
data=req.urlopen('JSON데이타 요청할 서버 주소').read().decode("utf-8")
#json모듈의 loads()함수로 파이썬 컬렉션으로 변환
dic=json.loads(data)
※데이터를 CSV 파일로 처리
CSV란 Comma-separated values의 약자로서 CSV 파일은
각 라인의 컬럼들이 콤마로 분리된 텍스트 파일 포맷이다.
간단한 형태의 CSV 파일은 문자열을 콤마로 split 하여 처리하면 된다,
그러나 데이타에 콤마가 포함된 경우 이중 인용부호로 감싸서 데이타 내의 콤마를
escape하기 때문에, 파이썬에 내장된 csv 모듈을 사용하여 .csv 파일을 처리하는 것이 유리하다.
-CSV 파일 읽기
1.csv모듈 import
2. reader(파일객체) 메소드로 읽는다
reader(파일객체)메소드는 Iterator 타입인 reader 객체반환
이때 리턴되는 reader 객체는 컬럼들을 나열한 리스트(list) 타입이다.
예제1]
#data.csv 파일 내용
'''
1,가길동,GA,1234,가산동
2,나길동,NA,5678,나산동
3,다길동,DA,9999,다산동
'''
import csv
f = open('data.csv', 'r', encoding='utf-8')
reader = csv.reader(f)
for line in reader:
print(line)
f.close()
-CSV 파일 쓰기
1.csv.writer(파일객체)메소드로 writer객체 얻는다
2.writer객체의 writerow()메서드를 통해 list 데이타를
한 라인씩 쓴다.
윈도우즈의 경우 csv 모듈에서 데이타를 쓸 때 각 라인 뒤에 빈 라인이 추가되는 문제가 있는데,
이를 없애기 위해 (파이썬 3 에서) 파일을 open 할 때 newline='' 와 같은 옵션을
지정한다 (파이썬 2의 경우는 newline 옵션 없이 바이너리 모드로 오픈하면된다)
예제2]
import csv
#리스트 형태의 테이타
f = open('data.csv', 'w', encoding='utf-8', newline='')
writer = csv.writer(f)
writer.writerow([1, "라길동",'LA',1999,'라산동'])
writer.writerow([2, "마길동",'MA',9991,'마산동'])
f.close()
#딕션너리 형태의 데이타
f= open('data.csv', 'w', encoding='utf-8', newline='')
fields = ['no', 'name', 'id', 'password','address']
writer = csv.DictWriter(f, fieldnames=fields)
writer.writeheader()
writer.writerow({'no':1, 'name':"라길동",'id':'LA','password':1999,'address':'라산동'})
writer.writerow({'no':1, 'name':"마길동",'id':'MA','password':9991,'address':'마산동'})
f.close()
※파이썬 스케줄링하기
1.schedule라이브러리 : 함수가 직관적이라 사용하기 편하다
https://pypi.org/project/schedule/
1-1. pip install schedule
1-2. 사용법
#1.schedule을 import한다
import schedule
import time
#2. 스케줄링하고자 하는 작업을 정의한다
def job():
pass
#3. 스케줄링을 한다
schedule.every(숫자).second.do(job) # 지정한 초단위마다 한번씩 실행
schedule.every(숫자).minutes.do(job) # 지정한 분단위마다 한번씩 실행
schedule.every().hour.do(job)#매 시간마다 실행
schedule.every().day.at("시:분").do(job) # 매일 지정한 시:분에 실행
schedule.every().monday.do(job) #매주 월요일 실행
schedule.every().monday.at("시:분").do(job)#매주 월요일 시:분에 실행
#4. 스케줄링을 실행한다
while True:
schedule.run_pending()
time.sleep(1)
이건 아나콘다용 가상환경 만들기
기본 가상환경(base)
conda create --name crawl python==3.10
파이썬 3.10버전으로 이름은 crawl으로 만듬
urllib01.py
#urllib.request 모듈 사용하기 1
import urllib.request as request
#urllib.request모듈의 urlretrieve()함수와 urlopen()함수로 HTML소스 스크래핑하기
#urlopen()함수 : HTTPResponse객체 반환
# HTTPResponse객체의 read()메소드로 html소스 얻을 수 있다
#urlretrieve()함수: html소스를 파일로 바로 다운받는 함수
#urlopen()함수
#request.urlopen('URL 주소') 혹은 request.urlopen(Request객체)
res=request.urlopen('https://www.naver.com')
print(f'value:{res},type:{type(res)}')#<class 'http.client.HTTPResponse'>
print(dir(res))
print('응답 코드:',res.status)
#응답헤더 얻기 1:HTTPResponse객체.headers
print(res.headers)
#응답헤더 얻기 2:HTTPResponse객체.getheaders()
print(res.getheaders())
print('-' * 50)
for name,value in res.getheaders():
print(f'{name} : {value}')
#응답헤더 얻기 3:HTTPResponse객체.getheader('헤더명')
print(res.getheader('Content-Type'))
#print(type(res.read()))#<class 'bytes'>
source=res.read().decode()#바이너리 문자열을 문자열로 변환
print(source)
with open('naver_urllib01-1.html','w',encoding='utf-8') as f:
f.write(source)
#urlretrieve()함수:('파일명', <http.client.HTTPMessage at 0x26fe9755df0>)튜플 반환
# 즉 ('파일명','응답헤더(HTTPMessage)')
tuple_=request.urlretrieve('https://www.naver.com',filename='naver_urllib01-2.html')
print(tuple_)
print(tuple_[0])#파일명
print(tuple_[1])#응답헤더
urllib02.py
#urllib.request 모듈 사용하기 2
import urllib.request as request
#urllib.request모듈의 urlretrieve()함수와 urlopen()함수로 이미지 스크래핑하기
#아래는 urllib.error.HTTPError: HTTP Error 403: Forbidden에러
#프로그램으로 요청한게 아니고 브라우저로 요청한거로 인식 되도록 요청헤더를 추가해야 한다
#request.urlopen('https://images.pexels.com/photos/3081487/pexels-photo-3081487.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500')
#urlopen(url:str)함수 호출시 403에러 해결
#urlopen(Request객체) 이때 Request객체 생성시 요청헤더를 추가한다
req=request.Request('https://images.pexels.com/photos/3081487/pexels-photo-3081487.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',headers={'user-agent':'Mozilla/5.0'})
res=request.urlopen(req)
binary=res.read()
with open('landscape1.jpg','wb') as f:
f.write(binary)
#urlretrieve()함수 호출시 403에러 해결
opener=request.build_opener()
opener.addheaders=[('user-agent','Mozilla/5.0')]#인자는 [(str,str)]
request.install_opener(opener)
request.urlretrieve('https://images.pexels.com/photos/3081487/pexels-photo-3081487.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500','landscape2.jpg')
urllib03.py
#※urllib3는 requests모듈 설치시 함께 설치된다. 고로 파일명을 urllib3.py로 하지 말아라
import urllib.request as request
#urllib.parse 모듈 사용하기
import urllib.parse as parse
#1.quote() 및 quote_plus()함수 : url인코딩하는 함수
query=input('검색어를 입력하세요?')
#검색어로 한글 입력시 UnicodeEncodeError발생
#codeEncodeError: 'ascii' codec can't encode characters in position 14-16
#해결책
#URL에 한글이 포함되면 URL인코딩해서 요청해야 한다.parse모듈로 URL을 인코딩
#파이참이 %ED%8C%8C%EC%9D%B4%EC%B0%B8 URL인코딩
encoded_qoute = parse.quote(query)#빈 공백이 %20
encoded_qoute_plus = parse.quote_plus(query)#빈 공백이 +로 인코딩(권장)
print(encoded_qoute,encoded_qoute_plus,sep='\n')
url=f'https://www.google.com/search?q={encoded_qoute_plus}'
req=request.Request(url=url,headers={'user-agent':'Mozilla/5.0'})
print(dir(req))
print(f'요청방식:{req.get_method()},요청 서버:{req.host}')
print('요청 헤더:{}'.format(req.headers))
print('요청 url:%s' % req.full_url)
res = request.urlopen(req)
source=res.read().decode()
with open('google.html','w',encoding='utf8') as f:
f.write(source)
#2. urlsplit(주소):URL을 각 부분으로 나눠 SplitResult객체 반환
urls = parse.urlsplit(url)
print(urls)
for url in urls:
print(url)
print(f'protocol:{urls.scheme},domain:{urls.netloc},path:{urls.path},query:{urls.query}')
#3. urlunsplit():나눈 URL을 합치는 함수
print(parse.urlunsplit(urls))
#4. urlencode(딕셔너리):딕셔너리를 쿼리스트링 형태로 인코딩하는 함수
# {키1:값1,키2:값2}를 키1=값1&키2=값2
#즉 쿼리스트링으로 문자열을 만들고 URL인코딩도한다(인코딩방식은 quote_plus()함수와 같다)
print(parse.urlencode({'q':'파이참','oq':'파이참'}))
#oq파라미터 포함해서 검색
url =f"https://www.google.com/search?{parse.urlencode({'q':query,'oq':query})}"
req=request.Request(url=url,headers={'user-agent':'Mozilla/5.0'})
res = request.urlopen(req)
source=res.read().decode()
with open('google_.html','w',encoding='utf8') as f:
f.write(source)
urllib04.py
#POST방식으로 요청하기
#urlopen('요청URL') 혹은 urlopen(Request(요청url)) : GET방식
#urlopen(Request(요청url,data=params,headers={})): POST방식
import urllib.request as request
import urllib.parse as parse
#GET방식 요청-데이타 전송(쿼리스트링으로)
params = parse.urlencode({'id':'kosmo','pwd':'1234','name':'한소인'})
headers={'user-agent':'Mozilla/5.0'}
url = 'https://nid.naver.com/nidlogin.login'
req = request.Request(f'{url}?{params}',headers=headers)
res=request.urlopen(req)
print(req.get_method())
print(res.status)
print(res.read().decode())
#POST방식 요청
'''
TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str
req = request.Request(url,headers=headers,data=params)
res=request.urlopen(req)
'''
req = request.Request(url,headers=headers,data=params.encode())
res=request.urlopen(req)
print(req.get_method())
print(res.status)
print(res.read().decode())
#스프링 서버로 POST방식요청(로그인)
url='http://127.0.0.1:9090/onememo/auth/LoginProcess.do'
params = parse.urlencode({'id':'kim','pwd':'1234'})
req = request.Request(url,headers=headers,data=params.encode())
res=request.urlopen(req)
with open('spring_login.html','w',encoding='utf8') as f:
f.write(res.read().decode())
requests01.py
#한글 파라미터가 있는 경우 url인코딩 해야한다 하지만 requests모듈은 한글 인코딩 불필요.
#표준 라이브러리가 아님으로 설치 필요
import requests
print(dir(requests))
res=requests.get('https://www.naver.com',headers={'user-agent':'Mozilla/5.0'})#requests.request(method='get',url='https://www.naver.com')와 같다
print(f'value:{res},type:{type(res)}')#<class 'requests.models.Response'>
print('응답코드:',res.status_code,sep='')
print('응답헤더:',res.headers,sep='')
print('응답바디(바이트 문자열):',res.content,'자료형:',type(res.content))#<class 'bytes'>
print('응답바디(문자열):',res.text,'자료형:',type(res.text))#<class 'str'>
print('네이버 인코딩 방식:',res.encoding)#UTF-8
with open('naver_requests.html','w',encoding='utf8') as f:
f.write(res.text)
'''
str -> bytes: encode()(str의 메소드)
bytes -> str: decode()(bytes의 메소드)
'''
#응답과 관련된 요청객체 얻기
req=res.request
print(f'value:{req},type:{type(req)}')
print('요청방식:',req.method,sep='')
print('요청URL:',req.url,sep='')
print('요청헤더:',req.headers,sep='')#{'User-Agent': 'python-requests/2.29.0', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive'}
requests02.py
#GET방식으로 요청 보내기
#방법1:requests.get(요청url)
#방법2:requests.request('GET',요청url)
import requests
url='https://images.pexels.com/photos/3081487/pexels-photo-3081487.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500'
#res = requests.get(url=url)#요청헤더 미 설정해도 Forbidden에러 안남
res = requests.request(method='get',url=url)
print('요청 방식:',res.request.method)
with open('scrapping.jpg', 'wb') as f:
f.write(res.content)
requests03.py
#POST방식으로 요청 보내기
#방법1:requests.post(요청url)
#방법2:requests.request('POST',요청url)
#로그인이 필요 없을때는 requests.post()
#로그인이 필요한 경우 세션이 필요하기 때문에 즉 브라우저로 요청하는게 아니라 프로그램으로 요청함으로
#1.session=requests.Session() 로 세션 객체를 얻고
#2.세션 객체로 session.post() 즉 마치 브라우저의 세션처럼
import requests
#[1. 세션이 필요없는 POST 요청]
url='http://localhost:9090/Annotation/RequestMappingBoth.do'
#res = requests.post(url=url,data={'id':'KIM','pwd':'1234'})#요청헤더 미 설정해도 Forbidden에러 안남
res = requests.request(method='POST',url=url,data={'id':'KIM','pwd':'9999'})
print('요청 방식:',res.request.method)
print('응답바디(HTML소스):',res.text)
#[2. 세션이 필요한 POST 요청]
session = requests.Session()
#세션객체로 post()
url='http://localhost:9090/onememo/auth/LoginProcess.do'
res = session.post(url=url,data={'id':'kosmo','pwd':'1234'})
print('요청 방식:',res.request.method)
print('상태 코드:',res.status_code,sep='')
print('응답헤더:',res.headers,sep='')
print('응답바디(HTML소스):',res.text)
requests04.py
#외부 REST API요청(JSONPlaceHolder)
import requests
#requests모듈에는 자바스크립트 JSON형태의 문자열을 파이썬의 리스트로 디코딩해주는 함수가 있다:json()
res= requests.get('https://jsonplaceholder.typicode.com/photos')
print(res.text)#<class 'str'>
print(type(res.json()))#<class 'list'>
photos=res.json()
for photo in photos:
for key,value in photo.items():
print(key,value,sep=' : ')
print('-' * 20)
requests05.py
#내가 만든 REST API서버에 OCR서비스 요청
'''
POST http://localhost:5000/ocr
파라미터명 base64
'''
import requests
import base64
import json
def image_to_base64(image_path):
with open(image_path, "rb") as f:
base64_bytes = base64.b64encode(f.read())
print(base64_bytes)#b'iVBORw0KGg~' <class 'bytes'>
base64_str=base64_bytes.decode("utf-8")
print(base64_str)
return base64_str
base64=image_to_base64('ocr.png')
res=requests.post('http://localhost:5000/ocr',
headers={'Content-Type':'application/json'},
data=json.dumps({'base64':base64}))
print(res.text)