반응형
파이썬으로 투명 배경의 이미지로 만드는 방법

아래 코드에서 pixel 배열에 R,G,B 값이 들어있으므로 원하는 컬러를 투명하게 처리할 수 있다.

색깔 범위를 +- 5~10정도 주면 좀 더 배경을 잘 제거 할 수 도 있을 것이다. 

from PIL import Image

# 이미지 파일 열기
image = Image.open("image.png")

# 새로운 alpha channel 생성
alpha_data = []
for pixel in image.getdata():
    if pixel[0] == 255 \
        and pixel[1] == 255 \
        and pixel[2] == 255:
        alpha_data.append(0)
    else:  # 그 외의 경우 alpha 값을 255로 설정
        alpha_data.append(255)
alpha_channel = Image.new("L", image.size)
alpha_channel.putdata(alpha_data)

# alpha channel을 이용하여 이미지의 배경을 투명하게 만듦
new_image = image.convert("RGBA")
new_image.putalpha(alpha_channel)

# 이미지 파일 저장
new_image.save("transparent_image.png")

색상 범위를 쉽게 주려면?  아래 코드 참고

# 색상 범위 설정
lower_color = (245, 245, 245)  # 검색할 색상 범위의 최소값
upper_color = (255, 255, 255)  # 검색할 색상 범위의 최대값


    if lower_color <= pixel <= upper_color:
        alpha_data.append(0)
    else:  # 그 외의 경우 alpha 값을 255로 설정
        alpha_data.append(255)

'Python' 카테고리의 다른 글

Drawing Plot, 투명 이미지 datauri 생성  (0) 2023.03.20
set에 set 추가? frozenset  (0) 2021.02.24
Jupyter Notebook 소스 복구  (0) 2020.06.16
Docker python venv 패키지 유지  (0) 2020.06.07
딕셔너리에서 키삭제  (0) 2019.12.07
반응형
포인트 리스트를 가지고 그림을 드로잉하고, 이것을 원하는 크기로 Resize 하고, 투명 이미지 datauri 만들기...
pointlist = '[(10,10)(20,20)(40,50)(60,80)][(10,80)(24,70)(40,60)(60,40)]'

# image 필드에 데이터가 없는 목록만 뽑아서 배치 작업을 수행한다.
def to_datauri(sn):
    sn = sn.strip()
    # 정규표현식으로 포맷 문자열에서 점 정보 추출
    point_regex = r"\(([-+]?\d+),([-+]?\d+)\)"
    strokes = sn.replace('[', '')
    strokes = strokes.split(']')
    strokes = [ s for s in strokes if s!='' ]

    # 그래프 그리기
    plt.figure()
    fig, ax = plt.subplots(figsize=(3, 2))
    ax.set_facecolor('none') # 배경 투명
    fig.patch.set_alpha(0) # 배경 투명
    # 축과 눈금 숨기기
    ax.axis('off')

    # 각 획별로 분리하여 그리기
    for stroke in strokes:
        points = re.findall(point_regex, stroke)
        if len(points)==0:
            continue
        x_list = [int(point[0]) for point in points]
        y_list = [int(point[1]) for point in points]
        ax.plot(x_list, y_list, color='black', lw=2)

    plt.gca().invert_yaxis()  # y축 뒤집기

    # 그래프 저장
    buf = io.BytesIO()
    plt.savefig(buf, format='png', bbox_inches='tight')
    buf_resized = buf

    ## resize 작업
    buf.seek(0)
    img = Image.open(buf)
    img_resized = img.resize((150,100), Image.Resampling.LANCZOS)  
    # img_resized = img.resize((150,100), Image.ANTIALIAS)  
    # sampling=Image.ANTIALIAS deprecated 되었다. 버전에 따라 위 둘 중 하나를 사용.
    buf_resized = io.BytesIO()
    img_resized.save(buf_resized, format=img.format)

    # buf대신 buf_resized를 변환
    buf_resized.seek(0)
    data_uri = 'data:image/png;base64,'+base64.b64encode(buf_resized.read()).decode('utf-8')
    plt.close()
    plt.clf()
    plt.close('all')
    img.close()
    img_resized.close()
    buf.close()
    buf_resized.close()

    return data_uri

이 함수를 사용하여 드로잉 데이터를 넣으면, datauri 텍스트가 출력된다.

시작,끝 따옴표를 제거한 텍스트를 복사해서 브라우저 URL창에 넣으면 드로잉된 투명이미지가 나온다.. (드래그해 보면, 선만 움직이는 것을 확인할 수 있다. 배경투명)

y축을 뒤집은 이유는? 모니터 스크린 좌표계에서 보통 좌상단이 (0,0) 이다.  plot에서는 좌하단이 (0,0)이다. 따라서 스크린 좌표계로 보이게 하려고 하였다. 

datauri가 아니라 파일로 저장하려면 plt.close() 전에  plt.savefig('test.png') 로 저장하면 된다.

 

'Python' 카테고리의 다른 글

투명 배경 이미지 만들기  (0) 2023.03.22
set에 set 추가? frozenset  (0) 2021.02.24
Jupyter Notebook 소스 복구  (0) 2020.06.16
Docker python venv 패키지 유지  (0) 2020.06.07
딕셔너리에서 키삭제  (0) 2019.12.07
반응형

파이썬으로 알고리즘 프로그래밍을 하다가 우연히 set에 set을 추가할 일이 있었다.

리스트에 리스트가 추가가 가능한 것 처럼, set도 되지 않을까??

생각해서 해보니, 안 되었다. set에는 immutable 즉, 변경불가한 데이터만 원소로 추가가 가능하였다. 

따라서 set에는 set, list 등 변화가 가능한 것들이 추가가 안 된다.

정말 안되나 하다가...  set을 추가할 방법을 찾았다. 그것은 frozenset.

한 줄 요약: 원소가 되는 set을 frozenset으로 캐스팅하여 사용한다!

더 이상 수정불가능한 immutable 타입으로 캐스팅하면 원소로 넣을 수 있다.

a = set()

# 리스트 추가 안됨.
a.add([1,2,3]) # TypeError: unhashable type: 'list'

# SET 도 추가 안됨.
b = set()
a.add(b) # TypeError: unhashable type: 'set'

# SET을 추가할 수 있는 방법??? FROZENSET!
a.add(frozenset(b)) # ok

 

'Python' 카테고리의 다른 글

투명 배경 이미지 만들기  (0) 2023.03.22
Drawing Plot, 투명 이미지 datauri 생성  (0) 2023.03.20
Jupyter Notebook 소스 복구  (0) 2020.06.16
Docker python venv 패키지 유지  (0) 2020.06.07
딕셔너리에서 키삭제  (0) 2019.12.07
반응형
jupyter_notebook_recover

jupyter notebook source recover

python 노트북 소스파일 복구

jupyter notebook 작업시 주의사항!!!
동일한 소스 코드 창을 여러 개 띄운 경우.
잘못하여 구 버전 창을 보고 저장을 했다면??? OverWrite!!!

신 버전 소스가 날아가는 경험을 하게 된다!!!
이제까지 작업한 것을 날리게 되는 것이다.
실수라고 생각할땐 이미 늦었다… 한숨이 나온다…

혹시나 하여 백업한게 없을까 찾아본다.

방금 작업한 디렉터리에 보니,

.ipynb_checkpoints 폴더가 있다. 
들어가서 동일한 소스코드명을 찾아보았다.
같은 이름의 파일이 있었다.
일단, 복사하여 사본을 만들어 놓고, 열어보았다.

오호… 럭키~~~
다행히도 수동 저장(덮어쓰기) 전에 자동 세이브된 파일이 남아 있었다.
알아두면 긴급시 이렇게 복구할 수 도 있습니다.
^^;

Author: crazyj7@gmail.com

'Python' 카테고리의 다른 글

Drawing Plot, 투명 이미지 datauri 생성  (0) 2023.03.20
set에 set 추가? frozenset  (0) 2021.02.24
Docker python venv 패키지 유지  (0) 2020.06.07
딕셔너리에서 키삭제  (0) 2019.12.07
파이썬 충돌해결 module conflict  (0) 2019.12.01
반응형
windows_ethereum_pkg_error

Windows Ethereum python module install error

ethereum python 패키지를 윈도우에 설치할 때 환경에 따라 ethash에서 alloca.h 에러가 나는데 이것을 해결하기 위한 방법이 있다.

ethash

  • ethereum 패키지를 설치하는 과정에서 pyethash 모듈을 빌드하다가 에러가 발생한다. (alloca.h 에러)
  • ethhash 소스를 받아 코드를 수정하여 설치한다.
    git clone https://github.com/ethereum/ethash
1. src/libethash/mmap_win32.c
아래 코드 추가
#pragma comment(lib, "Shell32.lib")
2. src/python/core.c
#include <alloca.h> 를
#include <malloc.h> 로 바꾼다.

pip install .
으로 설치한다.
이후에 다시 ethereum을 pip로 설치시도하면 ethash를 자꾸 새로 설치하려고 하면서 동일한 에러가 나고 롤백이 된다.

ethereum

  • ethereum 패키지 소스를 받아 의존성 수정하여 설치한다.
    https://github.com/ethereum/pyethereum/releases/tag/v2.3.2
    소스를 받아서 풀고
    requirements.txt 에서 ethash 설치하는 부분을 삭제한다. (이미 패치한것을 위에서 설치했으므로 건너뛰도록 하는 것이다.)
    pip install .
    으로 설치한다.

Author: crazyj7@gmail.com

'BlockChain' 카테고리의 다른 글

Solidity#2 HelloWorld  (0) 2019.12.06
Solidity 0.4 vs 0.5  (0) 2019.12.06
[ether02] 코인만들기  (0) 2019.11.10
[ether01] solidity 맛보기  (0) 2019.11.10
이더리움개발 환경 준비  (1) 2019.11.10
반응형
module_conflict

Python module conflict error

파이썬으로 외부의 여러 패키지들을 깔고 테스트하다 보면 가끔씩 충돌이 발생하여 이전에는 잘 되던 것들이 꼬이게 된다.
막상 경험해 보면 복구하는 것이 쉽지 않고 점점 더 꼬이는 악순환이 발생하여 나중에는 파이썬을 다시 설치하게 된다.
어떻게 복구하는 방법이 없을까?

먼저 가끔씩 현상황을 기록해 두자.

pip freeze > requirements.txt

  • 위와 같이 freeze 옵션을 사용하면 현재 설치된 모든 모듈의 버전들이 기록된다. 보통은 requirements.txt 로 많이 기록된 것을 볼 수 있다.
  • 나중에 저 목록을 한 번에 설치가 가능하다. install -r 옵션을 사용한다.

마지막에 설치/변경된 모듈들을 삭제.

  • 마지막에 설치/변경된 모듈들을 하나씩 삭제해 올라간다.
  • 그런데 마지막순으로 설치된 모듈들이 무엇인지 기억이 나지 않는다.

현재 python 환경(env)의 설치 경로들을 확인.
conda env list
python --version
코드로 라이브러리 위치 확인

import os, inspect
inspect.getfile(os)
'opt/anacoda3/lib/python3.7/os.py'

import web3
inspect.getfile(web3)
'/home/crazyj/myvenv/lib/python3.7/site-packages/web3/__init__.py'
  • 위와 같이 패키지 설치 경로를 확인한 다음 디렉터리로 가서 날짜를 확인한다.

ls -ltr : 마지막에 나온것들이 최근 설치/업데이트된 패키지들. (last modified time 기준으로 역순소팅)
위 마지막 패키지들을 pip uninstall로 하나씩 지워나가면서 테스트 한다.

모든 패키지 삭제하기

이것도 저것도 안된다면, 백업받은 패키지 목록대로 돌리기 위해 전부 삭제하고 다시 설치하자.

pip freeze | xargs pip uninstall -y
또는
pip freeze > requirements.txt
pip uninstall -r requirements.txt -y

패키지 목록 한번에 설치하기

pip install -r requirements.txt

Author: crazyj7@gmail.com

'Python' 카테고리의 다른 글

Docker python venv 패키지 유지  (0) 2020.06.07
딕셔너리에서 키삭제  (0) 2019.12.07
파이썬 개발환경/가상환경구축  (0) 2019.12.01
진법 표현 및 수 스트링 변환  (0) 2019.11.24
크롤링 BeautifulSoup 요약  (1) 2019.11.06
반응형
virtualenv

Python Virtual Env / Conda Env

파이썬 가상환경. 여러가지 버전의 파이썬을 동시에 사용할 수도 있고, 목적에 따라 가상환경을 만들어 따로 운영할 수 있다.
딥러닝용, 그래픽용, 서버 개발용 등등

virtual env 환경 생성

  • 설치된 버전 확인

    • pip --version
    • pip3 --version
    • pip install virtualenv
    • pip3 install virtualenv
  • 현재 폴더 아래 가상환경 생성. 주어진 환경이름으로 폴더가 생성된다.

    • virtualenv 이름 --python=pyton버전
    • virtualenv py37 --python=python3.7
    • 윈도우의 경우 안 된다면 --python=[python.exe fullpath]로 한다. 생략하면 현재 연결된 path의 python 버전으로 자동 인식.

가상환경으로 들어가기

  • source ./py37/bin/activate
  • 위 커맨드를 입력하여 실행하면 잘 되는데, shell script로 만들어 실행하면 작동하지 않는다.
  • 리눅스에서는 로그인 계정의 .bashrc에 alias=‘source …’ 으로 만들어 사용하자.
  • 윈도우는 source 대신 call을 사용하여 배치 파일로 만들면 된다.
    • py37.bat
      call c:\devtools\py37\scripts\activate
  • 작업이 끝나면 deactivate 로 빠져나간다.

가상 환경별로 원하는 패키지 설치

  • 가상환경 사용하다가 freeze로 requirements.txt를 생성해 주자. (나중에 한 번에 필요 모듈 설치시 편리하다.)
pip list
pip freeze > requirements.txt
pip install -r requirements.txt
pip install numpy matplotlib ipykernel jupyter requests

Jupyter Notebook/Lab에 venv 등록

  • pip install ipykernel
  • jupyter에 가상 환경 등록
python -m ipykernel install --user --name py37 
       --display-name py37

(–display-name은 생략해도 된다.)

Jupyter Notebook 실행하여 확인

  • jupyter notebook
    파일 목록 오른쪽 메뉴에 New에 환경이름이 추가되었는지 확인한다. 소스 편집기에서 Kernel에서 Change하여 원하는 커널 환경을 선택한다.
  • 모듈 로딩 경로가 맞는지 최종 확인
    • 설치한 패키지명을 import하여 경로를 확인한다.
    • import web3, inspect
    • inspect.getfile(web3)
	'/storage/crazyj/py37/lib/python3.7/site-packages/web3/__init__.py'
  • Jupyter notebook 기본 브라우저를 크롬으로 변경
설정 파일이 없을 경우 최초 생성
jupyter notebook --generate-config

편집
notepad %userprofile%\.jupyter\jupyter_notebook_config.py

수정 내용
c.NotebookApp.browser = 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s'

  • Jupyter notebook 암호 설정
$ jupyter notebook password
암호 입력

Conda (Anaconda) env

virtualenv 말고 conda로도 만들 수 있다.

가상 환경 전환

  • 현재 존재하는 가상 환경 목록
    conda env list

  • 가상환경 활성화
    conda activate [가상환경명]
    또는
    activate [가상환경명]

  • 가상환경 비활성화
    conda deactivate

가상환경 생성

conda create --name [가상환경명] python=3.7.3 tensorflow keras
파이썬 버전을 명시해 주고, 뒤에 추가할 패키지명들을 옵션으로 적어줄 수 있다.

가상환경 삭제

conda remove --name [가상환경명] --all

Author: crazyj7@gmail.com

'Python' 카테고리의 다른 글

딕셔너리에서 키삭제  (0) 2019.12.07
파이썬 충돌해결 module conflict  (0) 2019.12.01
진법 표현 및 수 스트링 변환  (0) 2019.11.24
크롤링 BeautifulSoup 요약  (1) 2019.11.06
크롤링(Crawl) 2편  (2) 2019.10.27
반응형
crawl2_webdriver

Crawling 2 WebDriver

브라우저로 볼때는 분명 데이터가 있는데, 크롤링으로 HTML을 가져와서 보면 없는 경우가 있다.
이것은 브라우저에는 JS를 구동기능이 포함되어 HTML 문서가 동적으로 변화하기 때문에 단순하게 네트웍으로 HTML 문서를 받은 것과 항상 일치한다는 보장이 없기 때문이다
따라서 브라우저처럼 작동하여 변화된 HTML을 만들면 원하는 정보를 얻을 수 있는데 이것이 web driver이다.

구글 크롬 브라우저의 경우 이러한 것을 제공한다.
파이썬에서는 selenium 패키지를 설치하고, 운영체제에는 ChromeDriver를 설치해야 한다.
중요한 것은 현재 크롬브라우저의 버전과 ChromeDriver의 버전이 일치해야 한다!!!
버전이 다르다면 작동하지 않을 것이다.

https://sites.google.com/a/chromium.org/chromedriver/downloads
image

여기에서 자신의 크롬브라우저와 같은 버전의 드라이버를 받는다. 드라이버는 실행파일인데, PATH에 연결된 경로에 실행파일을 복사하면 준비가 다 된것이다.

전에 실패한 실시간 기사 조회

전에 코드에서 html 을 urllib으로 가져오지 말고 web driver를 구동하여 가져와서 파싱해 보자.

from selenium import webdriver
from bs4 import BeautifulSoup

url = 'https://m.media.daum.net/m/media/economic'

options = webdriver.ChromeOptions()
options.add_argument('headless')
browser = webdriver.Chrome(chrome_options=options)
browser.implicitly_wait(3)

browser.get(url)
html = browser.page_source
soup = BeautifulSoup(html, 'html.parser')

subnews = soup.find("div", "section_sub")
realnews = subnews.find("div", "box_realtime")
print(realnews)

browser.quit()


output

<div class="box_g box_realtime">
<h3 class="tit_g">실시간 주요 경제 뉴스</h3>
<ul category="economic" class="list_thumb">
<li>
<a class="link_news #MAIN_NEWS#article @1" href="http://v.media.daum.net/v/20191023201603468?f=m">
<div class="wrap_thumb">
<img alt="삼성물산 '1조6천억 분식회계' 적발..수천억 손실이 순익 둔갑" class="thumb_g" height="68" src="//t1.daumcdn.net/thumb/F240x180ht.u/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fnews%2F201910%2F23%2Fhani%2F20191023201603606uvoz.jpg"/>
</div>
<div class="cont_thumb">
<strong class="tit_thumb">
<span class="txt_g">삼성물산 '1조6천억 분식회계' 적발..수천억 손실이 순익 둔갑</span>
<span class="txt_cp">5분전</span>
</strong>
</div>
</a>
</li>
<li>
<a class="link_news #MAIN_NEWS#article @2" href="http://v.media.daum.net/v/20191023191757086?f=m">
<div class="wrap_thumb">
<img alt='野, 기재부에 "민부론 검토자료 내놔라"..與 "제출 의무 없어"' class="thumb_g" height="68" src="//t1.daumcdn.net/thumb/F240x180ht.u/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fnews%2F201910%2F23%2Fnewsis%2F20191023191757773esif.jpg"/>
</div>
<div class="cont_thumb">
<strong class="tit_thumb">
<span class="txt_g">野, 기재부에 "민부론 검토자료 내놔라"..與 "제출 의무 없어"</span>
<span class="txt_cp">1시간전</span>

전에는 ul 태그 내부가 비었었는데 이제 내용을 가져올 수 있게 되었다.
코드를 정리하여 기사 제목만 가져와보자. 이것도 좀 더 쉽게 하려면 F12키로 개발자모드로 간 다음 추출할 부분에 대해 selector 값을 쉽게 가져올 수 있다.
image
selector를 적당히 수정하면 목록을 쉽게 추출할 수있다.

# news = soup.select('#kakaoContent > div.section_sub > div.box_g.box_realtime > ul > li:nth-child(1) > a > div.cont_thumb > strong > span.txt_g')
news = soup.select('#kakaoContent > div.section_sub > div.box_g.box_realtime > ul > li > a > div.cont_thumb > strong > span.txt_g')
for item in news:
    print(item.text)

output

삼성물산 '1조6천억 분식회계' 적발..수천억 손실이 순익 둔갑
野, 기재부에 "민부론 검토자료 내놔라"..與 "제출 의무 없어"
은행권 "예대율 낮춰라".. 예금 확보 비상
경기 하강기 커지는 재정 역할.."세계 주요국도 확장 정책"
文 시정 연설 두고 '소득주도성장 실패' 공방 벌인 여야(종합)
한진그룹 총수일가, GS홈쇼핑에 지분 팔아 상속세 마련?
홍남기 "법인세 인하 투자증가로 연결 안 돼..신중한 입장"
김영진, 기재위 국감서 '황교안 계엄령 개입' 의혹 언급..野 반발
[단독]에어부산, 괌에서 '기체결함'으로 긴급 회항..13시간 지연 출항
[단독]정부 '직무급 도입-임금체계 개편' 병합 논의

전에 단순한 방식으로 안되는 작업이 이제 원하는 부분을 깔끔하게 추출하였다.

추가로…

아래는 만약 같은 페이지내에서 뭔가를 클릭해야 내용이 더 보여서 그 내용도 추출하기 위한 작업이다.

다음 실시간 검색어 조회

모바일용 웹 주소를 이용하였다. 일반 PC용 주소로 사용하면 데이터가 많아서 느릴 수 있으니 텍스트 위주의 페이지로 접근하는 것이 더 용이하다.
중간에 보면 실시간 검색어 목록이 다 나오도록 확장 버튼을 클릭하는 것을 추가하였다.

from selenium import webdriver
from bs4 import BeautifulSoup

def getTop10Daum():
    url = "https://m.daum.net"

    # browser = webdriver.PhantomJS()
    # browser.implicitly_wait(3)

    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    # browser = webdriver.Chrome(options=options)
    # browser = webdriver.Chrome()
    browser = webdriver.Chrome(chrome_options=options)
    browser.implicitly_wait(3)

    browser.get(url)
    browser.save_screenshot("web1.png")

    # mAside > div.head_issue > div.roll_issue.\#searchrank\#rolling > strong > a

    # browser.find_element_by_xpath('//*[@id="mAside"]/div[1]/div[1]/strong/a').click()
    browser.find_element_by_css_selector('div.roll_issue.\#searchrank\#rolling > strong > a').click()
    browser.save_screenshot("web2.png")

    html = browser.page_source
    soup = BeautifulSoup(html, 'html.parser')
    # print(soup)
    notices = soup.select('div.realtime_layer div.panel')

    resultlist = []

    for n in notices:
        # print ('aria-hidden-', n['aria-hidden'])
        if n['aria-hidden']=='false':
            lis = n.select('li')
            for l in lis:
                result = dict()
                result['rank'] = l.select_one('.num_issue').text
                result['title']= l.select_one('.txt_issue').text
                result['url'] = l.a['href']
                # print(l.select_one('.num_issue').text)
                # print(l.select_one('.txt_issue').text)
                # print('href=',l.a['href'])
                resultlist.append(result)
    browser.quit()

    # print(resultlist)
    return resultlist


if __name__ == '__main__':
    items = getTop10Daum()
    for it in items:
        print(it['rank'], it['title'], it['url'])

output

1 서효림 https://m.search.daum.net/search?w=tot&q=%EC%84%9C%ED%9A%A8%EB%A6%BC&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
2 이다희 https://m.search.daum.net/search?w=tot&q=%EC%9D%B4%EB%8B%A4%ED%9D%AC&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
3 김칠준 변호사 https://m.search.daum.net/search?w=tot&q=%EA%B9%80%EC%B9%A0%EC%A4%80+%EB%B3%80%ED%98%B8%EC%82%AC&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
4 정경심 교수 https://m.search.daum.net/search?w=tot&q=%EC%A0%95%EA%B2%BD%EC%8B%AC+%EA%B5%90%EC%88%98&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
5 송성문 https://m.search.daum.net/search?w=tot&q=%EC%86%A1%EC%84%B1%EB%AC%B8&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
6 김준기 https://m.search.daum.net/search?w=tot&q=%EA%B9%80%EC%A4%80%EA%B8%B0&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
7 오재일 https://m.search.daum.net/search?w=tot&q=%EC%98%A4%EC%9E%AC%EC%9D%BC&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
8 김수미 아들 https://m.search.daum.net/search?w=tot&q=%EA%B9%80%EC%88%98%EB%AF%B8+%EC%95%84%EB%93%A4&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
9 인헌고등학교 https://m.search.daum.net/search?w=tot&q=%EC%9D%B8%ED%97%8C%EA%B3%A0%EB%93%B1%ED%95%99%EA%B5%90&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue
10 이승호 https://m.search.daum.net/search?w=tot&q=%EC%9D%B4%EC%8A%B9%ED%98%B8&DA=ATG&nil_mtopsearch=issuekwd&logical=issue&pin=issue

Author: crazyj7@gmail.com

'Python' 카테고리의 다른 글

진법 표현 및 수 스트링 변환  (0) 2019.11.24
크롤링 BeautifulSoup 요약  (1) 2019.11.06
웹 크롤링 Crawl 1편  (0) 2019.10.24
인코딩에러 cp949  (1) 2019.10.02
ipynb와 py 양방향 전환  (2) 2019.09.30
반응형
crawl1

Crawling 크롤링

파이썬으로 간단하게 Web 페이지 크롤링하기.

인터넷 상의 자료들을 프로그래밍을 하여 Web URL로 받아 분석하여 필요한 정보를 가공하는 작업.

1단계 HTML 그대로 받기

HTML이 있는 URL 주소를 입력하면 대부분 그대로 보이는 페이지를 긁어올 수 있다. (로그인 인증이 필요하거나 특정 조건이 필요한 경우는 고급 방식을 사용해야 한다.)

### daum 기사 수집  
import urllib.request  
from bs4 import BeautifulSoup  
  
url = 'https://m.media.daum.net/m/media/economic'  
  
conn = urllib.request.urlopen(url)  
# art_eco = conn.read()  
soup = BeautifulSoup(conn, "html.parser")  
  
# print(soup)  
with open('output.txt', 'wt', encoding='utf8') as f:  
    f.write(str(soup))

print로 출력할 수도 있지만 보통 내용이 많아 파일로 저장해서 분석한다.
스트링 검색으로 원하는 부분을 잘 찾는다.

2단계 HTML 파싱하여 필요한 부분만 뽑기

HTML 내용에서 일부만을 발췌하고 싶다면 HTML 구조를 파악하여 어떻게 필요한 부분만을 select 할 수 있는 방법을 알아야 한다. BeautifulSoup 모듈을 사용하면 그나마 쉽게(?) 추출할 수 있다.
보통 홈페이지의 HTML은 시일이 지나면 업데이트되어 구조가 변경될 경우 기존 select 규칙이 안먹힌다. 그 때 그 때 업데이트를 해주어야 정상적으로 동작할 것이다. (아래 예제가 안돌아가면 스스로 업데이트하길 바란다.)

파싱할 텍스트

<strong class="tit_thumb">  
<em class="emph_g"><a class="link_txt #series_title @2" href="/m/media/series/1366383">글로벌포스트</a></em>  
<a class="link_txt #article @2" href="http://v.media.daum.net/v/20191023082142459?f=m">中 암호화폐 투자자 "한국 시장은 고사 상태"</a>  
</strong>  
</li>  
<li>  
<a class="link_thumb #series_thumb @3" href="http://v.media.daum.net/v/20191023070002158?f=m">  
<img alt='[김현석의 월스트리트나우] "트럼프는 워런을 이기고 재선된다"' class="thumb_g" src="//img1.daumcdn.net/thumb/S176x136ht.u/?fname=https%3A%2F%2Fimg1.daumcdn.net%2Fnews%2F201910%2F23%2Fked%2F20191023070003367kwmc.jpg&amp;scode=media"/>  
</a>  
<strong class="tit_thumb">  
<em class="emph_g"><a class="link_txt #series_title @3" href="/m/media/series/465092">월스트리트나우</a></em>  
<a class="link_txt #article @3" href="http://v.media.daum.net/v/20191023070002158?f=m">"트럼프는 워런을 이기고 재선된다"</a>  
</strong>

태그로 가져오기

위에서 a태그들을 모두 가져와서 출력해 보자.
find_all은 리스트 타입으로 리턴한다. 앞에서부터 발견된 해당 태그들을 리스트 아이템으로 append 추가한다.
보통 너무 많이 출력되서 찾기가 힘들 정도이다. 하나씩 보자.

arta = soup.find_all("a")  
print(arta)

출력 결과

[<a class="link_daum #logo" href="http://m.daum.net/" id="daumLogo">
<img alt="Daum" height="25" src="//t1.daumcdn.net/media/news/news2016/m640/tit_daum.png" width="24"/>
</a>, <a class="tit_service #service_news" href="/m/media/" id="kakaoServiceLogo">뉴스</a>, <a class="link_relate link_entertain #service_enter" href="/m/entertain/">연예</a>, <a class="link_relate link_sport #service_sports" href="https://m.sports.media.daum.net/m/sports/">스포츠
                    </a>, <a class="link_search #GNB#default#search" href="http://mtop.search.daum.net/" id="link_search">
<span class="ico_media ico_search">통합검색</span>
</a>, <a class="link_gnb #media_home" href="/m/media/"><span class="txt_gnb">홈</span></a>, <a class="link_gnb #media_society" href="/m/media/society"><span class="txt_gnb">사회</span></a>, <a class="link_gnb #media_politics" href="/m/media/politics"><span class="txt_gnb">정치</span></a>, <a class="link_gnb #media_economic" href="/m/media/economic"><span class="screen_out">선택됨</span><span class="txt_gnb">경제</span></a>, <a class="link_gnb #media_foriegn" href="/m/media/foreign"><span class="txt_gnb">국제</span></a>, <a class="link_gnb #media_culture" href="/m/media/culture"><span class="txt_gnb">문화</span></a>, <a class="link_gnb #media_digital" href="/m/media/digital"><span class="txt_gnb">IT</span></a>, <a class="link_gnb #media_ranking" href="/m/media/ranking"><span class="txt_gnb">랭킹</span></a>, <a class="link_gnb #media_series" href="/m/media/series"><span class="txt_gnb">연재</span></a>, <a class="link_gnb #media_photo" href="/m/media/photo"><span class="txt_gnb">포토</span></a>, <a class="link_gnb #media_tv" href="/m/media/tv"><span class="txt_gnb">TV</span></a>, <a class="link_gnb #media_1boon" href="/m/media/1boon"><span class="txt_gnb">1boon</span></a>, <a class="link_gnb #media_exhibition" href="https://gallery.v.daum.net/p/home"><span class="txt_gnb">사진전</span></a>, <a class="link_thumb #article_thumb" href="http://v.media.daum.net/v/20191022192703507?f=m">
<img alt='WTO 개도국 지위 간담회 농민 반발로 파행..정부 "곧 결론낼 것"' class="thumb_g" src="//img1.daumcdn.net/thumb/S720x340ht.u/?fname=https%3A%2F%2Fimg1.daumcdn.net%2Fnews%2F201910%2F22%2Fyonhap%2F20191022192703823dgcc.jpg&amp;scode=media"/>
</a>, <a class="link_cont #article_main" href="http://v.media.daum.net/v/20191022192703507?f=m">
<strong class="tit_thumb">WTO 개도국 지위 간담회 농민 반발로 파행..정부 "곧 결론낼 것"</strong>
<span class="info_thumb"><span class="txt_cp">연합뉴스</span><span class="ico_news ico_reply">댓글수</span>25</span>
</a>, <a class="link_relate #article_sub @1" href="http://v.media.daum.net/v/20191022201613686?f=m">

클래스와 ID에 주목하라

보통 태그로 가져오게되면 여러군데 있는 정보들이 마구 섞여서 나온다. index 번호를 잘 찾는다 해도 금방 변경될 수 있다.
그나마 좀 나은 방법은 일반적으로 태그들의 속성이나 클래스를 두어 카테고리화하여 작성한 경우가 많으므로 그 정보들로 데이터를 잘 필터링해야 한다.
클래스로 검색하려면 soup.find 또는 find_all에서 class_=“클래스명” 지정해 주고, ID로 검색하려면 파라미터에 id=“아이디” 를 추가한다.
위 a 태그들 중에 기사 제목같은 것만 뽑고 싶은데, 클래스를 잘 보면 link_news 라고 된 부분만 추출해 보자.

arta = soup.find_all("a", class_='link_news')  
print(arta)

output

[<a class="link_news #RANKING#popular_female#article @1" href="http://v.media.daum.net/v/20191022040803988?f=m">
<em class="txt_age emph_g2">
<span class="num_news age20">20</span>대<span class="txt_arr">↓</span> </em>
                                        심상찮은 경제 2위 중국·4위 독일.. R의 공포 급속 확산
                                    </a>, <a class="link_news #RANKING#popular_female#article @2" href="http://v.media.daum.net/v/20191023143008200?f=m">
<em class="txt_age emph_g2">
<span class="num_news age30">30</span>대                                        </em>
                                        '내일채움공제' 첫 5년 만기자 탄생..중기부 "정책 확대·개선하겠다"
                                    </a>, <a class="link_news #RANKING#popular_female#article @3" href="http://v.media.daum.net/v/20191023161257078?f=m">
<em class="txt_age emph_g2"> 

어느 정도 뽑히면 이제 내부를 탐색

a 태그중 link_news 클래스 속성이 있는 것을 다 뽑았다. 여기서 딱 제목만 뽑고 싶은데…
태그내에 있는 텍스트만 추출하면?
a태그 하나씩 가져와서 텍스트만 출력하는데 텍스트 앞뒤 공백을 제거하자.

arta = soup.find_all("a", class_='link_news')  
for art in arta:  
    print(art.text.strip())

output

20대↓ 
                                        심상찮은 경제 2위 중국·4위 독일.. R의 공포 급속 확산
30대                                        
                                        '내일채움공제' 첫 5년 만기자 탄생..중기부 "정책 확대·개선하겠다"
40대                                        
                                        액상형 전자담배 '사용자제→중단' 권고..청소년 즉시중단

거의 다 나온 것 같은데, 쓸데없는 스트링이 더 있었다. 잘 보면 em 태그에 있는 것이 연령대 스트링이 추가된 것이다. 뒤에 기사제목이 별도의 태그가 없어서 태그로 추출도 어렵다.
이때는 내용들을 분해해서 list로 받아 index를 찾으면 된다. 하위 개체들 중 마지막이 해당 텍스트가 될 것이다.

arta = soup.find_all("a", class_='link_news')  
for art in arta:  
    print( art.contents[-1].strip() )

output

'내일채움공제' 첫 5년 만기자 탄생..중기부 "정책 확대·개선하겠다"
환자 1명이 '졸피뎀' 1만1456정 구입..국내 처방환자 176만명
액상형 전자담배 '사용자제→중단' 권고..청소년 즉시중단
돌아온 미세먼지의 나날들..'잿빛 하늘' 내년 봄까지 이어질 듯
구조조정 나선 LG디스플레이, 올해 적자 1조원 넘어설 듯
정부 "'개도국 포기' 논의" 농민들 불렀지만..시작부터 '아수라장'
경영난 위워크, 결국 손정의 품으로.."100억달러 더 투입"
이탄희 "검찰 전관예우 더 심각, 전화 한통 값 수천만원"

깔끔하게 제목만 뽑을 수 있었다.

좀 더 편하게 찾을 수는 없을까?

브라우저의 개발자 모드(F12 키를 누르면 나온다.)에서 원하는 텍스트를 찾아서 검사 또는 element 보기를 하면 해당 텍스트의 상위 태그 및 속성 정보들을 모두 볼 수 있다. 오른쪽창에서 해당 텍스트 위치가 있는 소스로 이동한다. 하단보면 태그 구조가 나온다.
이를 기반으로 필터링 규칙을 잘 잡으면 빨리 찾을 수 있을 것이다.
crawl1

위의 부분을 한 번 찾아보려고 시도했는데…

subnews = soup.find("div", "section_sub")  
realnews = subnews.find("div", "box_realtime")  
print(realnews)  
  
news = soup.find("span", "txt_g")  
print(news)

결과는

<div class="box_g box_realtime">
<h3 class="tit_g">실시간 주요 경제 뉴스</h3>
<ul category="economic" class="list_thumb">
</ul>
<a class="link_more #MAIN_NEWS#more" href="#none">더보기<span class="ico_news"></span></a>
</div>
None

안타깝게도 정보가 없다. 우리가 원하는 정보는 list_thumb 클래스ul 태그 내부인데 비어 있다.
실제로 이러한 경우가 종종 있다. 이 경우는 보통 html을 요청했을 때, javascript가 포함되어 브라우저에서 작동시켜야 내용이 채워지는 경우들이다. 따라서 html 자체만을 보는 것으로는 원하는 결과를 얻을 수 없다.

귀찮지만 이럴때는 다른 방식을 사용해야 한다.
가상의 브라우저를 만들어 JS를 구동시킨 결과를 파싱하면 되는 것이다.

다음화에서 계속…

Author: crazyj7@gmail.com

'Python' 카테고리의 다른 글

크롤링 BeautifulSoup 요약  (1) 2019.11.06
크롤링(Crawl) 2편  (2) 2019.10.27
인코딩에러 cp949  (1) 2019.10.02
ipynb와 py 양방향 전환  (2) 2019.09.30
ipynb 노트북 파일 형상관리  (1) 2019.09.27
반응형
flask2

초간단 웹서버 만들기2

1편과 같은 코드를 좀 더 간단하게 줄일 수 있다.

annotation을 추가하면 좀 더 직관적으로 보기가 편하다.
사용 방법은 URL과 method를 연결할 함수 정의부 앞에 추가해 주면 된다.

다음은 간결해진 코드이다. (이번에는 로그 기능을 off하였다)

'''
test api server
'''

from flask import Flask, request
from flask_restful import Resource, Api
from flask.views import MethodView

import logging
import json,base64

import os, sys
import datetime
import threading, time

app = Flask(__name__)

# log = logging.basicConfig(filename='testsvr.log', level=logging.INFO)
# 로깅을 전부 끄기
log = logging.getLogger('werkzeug')
log.disabled = True
app.logger.disabled = True

'''
/apitest1
'''
@app.route('/apitest1', methods=['GET'])
def apitest1_get():
    data = request.args
    print('recv:', data)  # dictionary
    abc = data.get('abc')
    if abc :
        result = 'This is GET method!'+str(abc)
    else:
        result = 'Hello World! input abc'
    return result

@app.route('/apitest1', methods=['POST'])
def apitest1_post():
    # get과 동일하게 작동
    return apitest1_get()


'''
/sum
'''
@app.route('/sum', methods=['GET'])
def sum_get():
    data = request.args
    print('recv:', data)  # dictionary
    return 'Hello.'

@app.route('/sum', methods=['POST'])
def sum_post():
    logging.info('sum test')
    # print('request.data=', request.data)  # binary data read all
    data=request.get_json(force=True) # parse json string
    print('request.json=', data)
    a = data['a']
    b = data['b']
    now = datetime.datetime.now()
    print(now)
    timestr = now.strftime('%Y%m%d %H:%M:%S')
    result = {
        'sum':int(a+b),
        'time':timestr
    }
    logging.info('result='+json.dumps(result))
    return result

port = 18899
if __name__=='__main__':
    print('Start Server... port=', port)
    logging.info('start server')
    app.run(host='0.0.0.0', port=port, debug=False)
    # 디버그 모드로 하면 소스 수정시 자동으로 서버 재시작이 된다.


Written with StackEdit.

'Python' 카테고리의 다른 글

ipynb와 py 양방향 전환  (2) 2019.09.30
ipynb 노트북 파일 형상관리  (1) 2019.09.27
초간단 웹API서버만들기  (0) 2019.09.25
그래프 리셋(seaborn plot graph reset)  (0) 2019.09.20
JupyterLab에서 Python Script(.py)실행하기  (0) 2019.09.19

+ Recent posts