2019. 10. 30.

[python] 크롤링 데이터를 mysql에 삽입

이전 포스트(https://coashanee5.blogspot.com/2019/10/blog-post_29.html)는 공공기관의 채용공고 사이트의 검색결과를 수집하여 기업명과, 공고URL을 출력하였다. 이번 포스트에서는 수집한 내용을 데이터베이스에 넣어 보도록 하겠다.

1. 우선 mysql을 설치를 한 후, 데이터를 넣기 위한 데이터베이스를 만든다. 
create DataBase scraping;
2. 이번에는 데이터를 저장할 테이블을 생성한다. 
create Table job_offer (id BIGINT(7) NOT NULL AUTO_INCREMENT, comp VARCHAR(200), title VARCHAR(200), URL VARCHAR(1000), created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id));

3. 기존 소스에 DB연결과 데이터를 저장하는 내용을 추가한다.

# 공공기관 채용정보에서 정보통신 공고만 추려서 리스팅하는 소스
import requests
from bs4 import BeautifulSoup
from urllib.request import urlopen
import re
import ssl
import datetime
import pymysql
context = ssl._create_unverified_context()


# url을 변수에 삽입하여 저장한다.
url = "https://job.alio.go.kr/recruit.do?pageNo=1&param=&search_yn=Y" \
      "&idx=&recruitYear=&recruitMonth=&detail_code=R600020&location=R3010&work_type=R1010" \
      "&work_type=R1030&career=R2020&education=R7010&education=R7040&education=R7050" \
      "&education=R7060&replacement=N&s_date=2019.03.12&e_date=2019.10.12&org_name=&title=&order=REG_DATE"

conn = pymysql.connect(host='127.0.0.1', user='root',passwd='test1234', db='mysql')
cur = conn.cursor()
cur.execute("USE scraping")

html = urlopen(url, context=context)
bsObj = BeautifulSoup(html.read(), "html.parser")

table = bsObj.find("table",class_="tbl type_03")

def extractNumber(word):
    i = int(re.findall('\d+', word)[0])
    return i

def store(comp, title, URL):
    cur.execute(
        "INSERT INTO job_offer (comp, title, URL) VALUES (\"%s\", \"%s\", \"%s\")", (comp, title, URL)
    )
    cur.connection.commit()

list = []
trs = table.tbody.findAll("tr")
for idx, tr in enumerate(trs):
    title = tr.select("td")[2].get_text().strip() # 제목
    comp = tr.select("td")[3].get_text().strip() # 기업명
    a = extractNumber(tr.select("td")[2].find("a").attrs['onclick'])

    new_url = "https://job.alio.go.kr/recruitview.do?pageNo=1&param=&search_yn=Y&idx={0}" \
              "&recruitYear=&recruitMonth=&detail_code=R600020&location=R3010&work_type=R1010" \
              "&work_type=R1030&career=R2020&education=R7010&education=R7040" \
              "&education=R7050&education=R7060&replacement=N&s_date=2019.03.12" \
              "&e_date=2019.10.12&org_name=&title=&order=REG_DATE".format(a)
    print(idx, title, comp, new_url)
    store(comp, title, new_url)

cur.close()
conn.close()

실행결과, 다음과 같이 데이터가 저장되는 것을 확인할 수 있다.


Continue reading

2019. 10. 29.

[python] 공공기관 채용정보시스템의 채용공고 출력하는 파이썬코드

공공기관 채용정보시스템에서 원하는 공고를 검색하여 크롤링하는 소스이다.

# 공공기관 채용정보에서 정보통신 공고만 추려서 리스팅하는 소스
import requests
from bs4 import BeautifulSoup
from urllib.request import urlopen
import re
import ssl
import datetime
context = ssl._create_unverified_context()


# url을 변수에 삽입하여 저장한다.
url = "https://job.alio.go.kr/recruit.do?pageNo=1&param=&search_yn=Y" \
      "&idx=&recruitYear=&recruitMonth=&detail_code=R600020&location=R3010&work_type=R1010" \
      "&work_type=R1030&career=R2020&education=R7010&education=R7040&education=R7050" \
      "&education=R7060&replacement=N&s_date=2019.03.12&e_date=2019.10.12&org_name=&title=&order=REG_DATE"

html = urlopen(url, context=context)
bsObj = BeautifulSoup(html.read(), "html.parser")

table = bsObj.find("table",class_="tbl type_03")

def extractNumber(word):
    i = int(re.findall('\d+', word)[0])
    return i

list = []
trs = table.tbody.findAll("tr")
for idx, tr in enumerate(trs):
    title = tr.select("td")[2].get_text().strip() # 제목
    gName = tr.select("td")[3].get_text().strip() # 기업명
    #place = tr.select("td")[4].get_text().strip().replace("\t","").replace("\r","").replace("\n","") # 장소
    #type = tr.select("td")[5].get_text().strip() # 고용 형태
    a = extractNumber(tr.select("td")[2].find("a").attrs['onclick'])

    new_url = "https://job.alio.go.kr/recruitview.do?pageNo=1&param=&search_yn=Y&idx={0}" \
              "&recruitYear=&recruitMonth=&detail_code=R600020&location=R3010&work_type=R1010" \
              "&work_type=R1030&career=R2020&education=R7010&education=R7040" \
              "&education=R7050&education=R7060&replacement=N&s_date=2019.03.12" \
              "&e_date=2019.10.12&org_name=&title=&order=REG_DATE".format(a)
    #list.append(title + ", " + gName + ", "+new_url)
    print(idx, title, gName, new_url)
#print (list)

실행 결과는 아래와 같다. 



이후에는 크롤링 결과를 1) 엑셀 다운로드, 2) 메일 전송 3) 웹 서버에 띄우기 이런 정도로 포스팅을 해 볼까 생각중이다.

Continue reading

구글 블로거 꾸미기 -5 google blog 에서 소스코드 하이라이트 (highlight)

블로그 성격상 소스코드를 작성할 일이 많은데, 소스코드를 멋지게 작성하는 방법을 소개한다.

1. Highlight.js
코드 구문 강조를 위한 자바스크립트 라이브러리이다. 자동으로 언어를 감지하여 알맞는 표식을 삽입한다.

  • http://highlightjs.org/ 사이트에서 다운로드가 가능하다.

홈페이지에 보면 hosted와 custom package 두 가지 방법이 있다고 나와 있는데, google blog는 hosted 방식을 사용하면 된다. 아래 소스를 html 소스 중 <head></head> 안에 삽입하면 사용할 준비는 끝이다.
<link rel="stylesheet" href="//cdn.jsdelivr.net/highlight.js/8.7/styles/monokai_sublime.min.css" />
<script src="//cdn.jsdelivr.net/highlight.js/8.7/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
이제 포스팅 할때 <pre><code>소스코드 </code></pre> 이렇게 사용하면 된다. 간혹 언어를 인식하지 못하는 경우가 있는데 그럴 경우는 <pre><code="language-html>소스코드 </code></pre> 이런식으로 사용하고자 하는 언어를 입력하면 된다.


import execjs
execjs.eval("'red yellow blue'.split(' ')")

ctx = execjs.compile("""
function add(x, y) {
return x + y;
}
""")

print(ctx.call("add", 1, 2))

파이썬 코드를 예시로 들면 이런 형태의 디자인이 된다. 또한 css 파일의 링크를 바꾸면 원하는 디자인으로 테마를 마음대로 바꿀 수 있다.

** TIPS
가끔 다른 종류의 태그가 삽입되면 하이라이트가 작동 못하는 경우가 있는데, 이 경우 해당 사이트(http://accessify.com/tools-and-wizards/developer-tools/quick-escape/default.php)에서 코드를 넣고 스크립트를 치환하여 시도해보자.

예를들면, <strong>굵게</strong> 를 &lt;strong&gt;굵게&lt;/strong&gt;  이렇게!

Continue reading

2019. 10. 27.

구글 블로거 꾸미기 -4 글머리 기호(리스트) 기능 활성화

구글 블로그에서 글을 작성할때 아래와 같이 '글머리 기호' 기능이 필요할 때가 있다. 

  • AAA
  • BBB
  • CCC 이런 기능을 말함
그러나 어처구니 없게도 글을 작성할때는 되는가 싶다가도 게시하면 글머리가 사라진다.


1. '글머리 기호(리스트)' 기능 활성화
- 테마 -> HTML편집 -> 검색 -> 아래와 같이 수정
- 수정 전
.widget ul {list-style: none;margin : 1.5em 0 0;}

- 수정 후
.widget ul {
  list-style: disc; ! list-style: none
  margin: 0 0 0 0; ! margin: 1.5em 0 0;
  padding: 0 0 0 10px;
}
2.  '글머리 기호(리스트)' 앞 간격 조정

- 1번의 위젯 소스에서 padding 항목에 숫자를 수정하면된다. 

3. '글머리 기호(리스트)' 위 간격 조정

- 1번의 위젯 소스에서 margin 항목에 숫자를 수정하면된다. 

4. '글머리 기호(리스트)' 간 높이 간격 조정
- 아래와 같이 설정
.widget ul li {margin-bottom: 0em;}

Continue reading

구글 블로거 꾸미기 -3 피드 구독하기 기능 삭제

처음 블로거를 시작하면 하단에 "피드 구독하기: 게시물(Atom) 이라는 정체를 알수 없는 기능이 보여진다. 페이지를 볼때는 "피드 구독하기: 댓글(Atom) 도 있다.
사실상 거의 필요없는 기능이라 생각되어 기능을 제거하기로 했다.

1. "피드 구독하기:게시물(Atom)" 이 표시되지 않도록 설정
- 테마 -> 템플릿 -> 맞춤설정 -> 고급 -> CSS추가 -> 아래 코드 삽입
.blog-feeds{display:none;}
2. "피드 구독하기:댓글(Atom)"이 표시되지 않도록 설정
- 테마 -> 템플릿 -> 맞춤설정 -> 고급 -> CSS추가 -> 아래코드 삽입
.post-feeds {display:none;}

Continue reading

구글 블로거 꾸미기 -2 우클릭, 드래그 방지

자신의 블로그에서 우클릭, 드래그가 안되게 하고 싶어하는 경우가 있을 것이다.

1. 우클릭 방지
- 관리페이지 > 테마 > HTML 편집
- Ctrl + F 로 </body> 를 찾은 후 바로 위에 아래 코드를 삽입한다. 

 <script language=javascript>  
 <!--  
   
 var message="";  
   
 function clickIE()  
 {  
  if (document.all) {  
   (message);return false;}  
 }  
   
 function clickNS(e)  
 {  
 if (document.layers||(document.getElementById&&!document.all)) {   
  if (e.which==2||e.which==3) {(message);return false;}}  
 }  
   
 if (document.layers){  
  document.captureEvents(Event.MOUSEDOWN);document.onmousedown=clickNS;}  
 else{  
  document.onmouseup=clickNS;document.oncontextmenu=clickIE;}  
 document.oncontextmenu=new Function("return false")  
   
 // -->  
 </script> 

2. 드래그 방지
- 테마 > 템플릿 > 맞춤설정 > 고급
- CSS 추가를 통해 아래의 코드 삽입

html, body, div, span, object,  
 form, input, h1, h2, button, label, a, img {  
  -moz-user-select: none;  
  -ms-user-select: none;  
  -webkit-user-select: none;  
  /* this will work for QtWebKit in future */  
  -webkit-user-drag: none;  
 }  
   
 input[type=text] {  
  -moz-user-select: text;  
  -webkit-user-select: text;  
 } 

참조

  • http://ielselog.blogspot.com/2012/09/blog-post.html

Continue reading

2019. 10. 26.

구글 블로거 꾸미기 -1 스킨, 나눔고딕 폰트 적용

약 4년동안 나름 비주류인 구글 블로그를 하면서 많은 시행착오를 겪었었다. 지금도 고난(?)은 진행중이지만 나와 같은 시행착오를 겪고 있는 사람들에게 도움이 되었으면 하는 바램에 간단하게 나마 글을 작성한다.

1. 이미 만들어진 스킨을 이용하자.
구글 블로거는 HTML과 CSS 등을 기본적으로 요구하기 때문에 진입장벽이 타 블로그 보다는 높은 편이다. 그럼에도 불구하고 여러 스킨들을 제공하기 때문에 이를 적용하여 조금씩 수정해가면 나름 만족할 수준의 블로그를 만들 수 있을 것이다.

  • http://newbloggerthemes.com/
  • http://btemplates.com/

구글 블로그 스킨을 다루는 여러 사이트가 있지만 위 두 사이트를 추천한다. 다른 블로거들도 많이 이용하는 것 같다.

2. 폰트 적용은 어떻게?
스킨을 적용하니 블로그는 디자인은 바뀌었는데 폰트 적용부터 막막하다. HTML CSS 에 능숙하다면야 문제없겠지만, 능숙하지는 않다. 
결국 구글검색 후 블로그 관리페이지 > HTML편집 > .post-body 를 검색해서 폰트 수정했다. 그러나 전체 폰트를 조정할지 특정 문구의 폰트를 수정할지는 스킨에 따라 다르므로, 약간의 삽질이 필요할 것이다. 
  • http://smartbloggertips.blogspot.com/2013/08/change-font-size-of-blogger-posts.html
** blogger 에 나눔고딕 폰트 적용

- 테마 -> HTML편집 -> <head> 아래에 아래 코드 추가
<link rel='stylesheet'  href='http://fonts.googleapis.com/earlyaccess/nanumgothic.css'/> 
 - 그 후, 적용하려는 부분에 font-family: 'Nanum Gothic'; 을 추가한다
예시) body, h1, h2, h3, h4, a, div, input, p, span, td, label, select, textarea, iframe {
    font-family: 'Nanum Gothic';
}

3. "레이블이 blogger인 게시물을 표시합니다." 폰트 사이즈 변경 및 제거

아니 이건 뭔데 이런 촌스러운 모습을 하고 있는것인가. 
블로거에서 태그를 선택하면, 해당 태그를 갖고 있는 글들이 검색된다. 이때 위와 같은 메시지가 출력이 된다. 그러나 미관상 좋지 않기 때문에 제거하기로 했다. 

- 폰트 사이트 설정
관리페이지 > HTML 편집
.status-msg-wrap{  
font-size:24px;
}
- 보이지 않게 제거
.status-msg-wrap{  
display: none; 
}



Continue reading

2019. 10. 18.

[python] 아나콘다(anaconda) 에서 jupyter notebook 실행시 에러 발생

문제.
- 아나콘다 에서 jupyter notebook 을 실행 할때 해당 경로에 가서 명령어(C:\Users\dojang>C:\Users\dojang\Anaconda3\python.exe -m notebook --notebook-dir C:\project) 를 입력만 하면 되었다. (회사 환경에서는)
- 그런데 집에서는 "ImportError: DLL load failed: 지정된 모듈을 찾을 수 없습니다." 라는 오류가 발생한다.

해법.
- 문제의 원인은 찾지 못했지만 해결책은 찾았다. conda 환경을 갖추고 거기서 주피터를 실행한다
- cd C:\Users\ABC\Anaconda3\Scripts -> activate.bat -> jupyter.exe notebook

Continue reading

2019. 10. 15.

[python] requests 로 로그인 후 크롤링

requests 로 로그인 하고 BeautifulSoup으로 데이터 가져오기


import requests
from bs4 import BeautifulSoup

login_url = 'http://www.hanbit.co.kr/member/login_proc.php'

user = ''
password = ''

# requests.session 메서드는 해당 reqeusts를 사용하는 동안 cookie를 header에 유지하도록 하여
# 세션이 필요한 HTTP 요청에 사용됩니다.
session = requests.session()

params = dict()
params['m_id'] = user
params['m_passwd'] = password

# javascrit(jQuery) 코드를 분석해보니, 결국 login_proc.php 를 m_id 와 m_passwd 값과 함께
# POST로 호출하기 때문에 다음과 같이 requests.session.post() 메서드를 활용하였습니다.
# 실제코드:
res = session.post(login_url, data = params)

# 응답코드가 200 즉, OK가 아닌 경우 에러를 발생시키는 메서드입니다.
res.raise_for_status()

# 'Set-Cookie'로 PHPSESSID 라는 세션 ID 값이 넘어옴을 알 수 있다.
# print(res.headers)

# cookie로 세션을 로그인 상태를 관리하는 상태를 확인해보기 위한 코드입니다.
# print(session.cookies.get_dict())

# 여기서부터는 로그인이 된 세션이 유지됩니다. session 에 header에는 Cookie에 PHPSESSID가 들어갑니다.
mypage_url = 'http://www.hanbit.co.kr/myhanbit/myhanbit.html'
res = session.get(mypage_url)

# 응답코드가 200 즉, OK가 아닌 경우 에러를 발생시키는 메서드입니다.
res.raise_for_status()

soup = BeautifulSoup(res.text, 'html.parser')

# Chrome 개발자 도구에서 CSS SELECTOR를 통해 간단히 가져온 CSS SELECTOR 표현식을 사용
he_coin = soup.select_one('#container > div > div.sm_mymileage > dl.mileage_section2 > dd > span')

# 다음과 같이 class를 .mileage_section2 로 그리고 그 하부 태그중에 span이 있다는 식으로 표현도 가능함
# he_coin = soup.select_one('.mileage_section2 span')

print ('mileage is', he_coin.get_text())

출처

Continue reading

2019. 10. 14.

[python] 네이버 open api 를 통한 크롤링 수집

소스코드

ㅇㅇㅇ
import urllib.request
import json

client_key = '키 값'
client_secret = '시크릿 값'

# 한글등 non-ASCII text를 URL에 넣을 수 있도록 "%" followed by hexadecimal digits 로 변경
# URL은 ASCII 인코딩셋만 지원하기 때문임
encText = urllib.parse.quote_plus("스마트폰")
# print(encText)

naver_url = 'https://openapi.naver.com/v1/search/news.json?query=' + encText

# urllib.request.Request()는 HTTP Header 변경시에 사용함
# 네이버에서도 다음 HTTP Header 키를 변경해야하기 때문에 사용함
# HTTP Header 변경이 필요없다면, 바로 urllib.request.urlopen()함수만 사용해도 됩
request = urllib.request.Request(naver_url)
request.add_header("X-Naver-Client-Id",client_key)
request.add_header("X-Naver-Client-Secret",client_secret)

# urllib.request.urlopen 메세드로 크롤링할 웹페이지를 가져옴
response = urllib.request.urlopen(request)


# getcode() 메서드로 HTTP 응답 상태 코드를 가져올 수 있음
rescode = response.getcode()

# HTTP 요청 응답이 정상적일 경우, 해당 HTML 데이터를 수신되었기 때문에 필요한 데이터 추출이 가능함
# HTTP 요청에 대한 정상응답일 경우, HTTP 응답 상태 코드 값이 200이 됩니다.
if(rescode == 200):
# response.read() 메서드로 수신된 HTML 데이터를 가져올 수 있음
response_body = response.read()
# 네이버 Open API를 통해서 수신된 데이터가 JSON 포멧이기 때문에, 
# JSON 포멧 데이터를 파싱해서 사전데이터로 만들어주는 json 라이브러라를 사용
data = json.loads(response_body)
# json.loads() 메서드를 사용해서 data 에 수신된 데이터를 사전 데이터로 분석해서 자동으로 만들어줌
#print (data['items'][0]['title'])
#print (data['items'][0]['description'])
print(data)
else:
print("Error Code:" + rescode)

출처

Continue reading

2019. 10. 11.

[python] 네이버 검색 정보 크롤링해서 DB에 넣기

import requests
from bs4 import BeautifulSoup
from urllib.request import HTTPError
import pymysql
import datetime
headers = {'User=Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'}

def blog_crawling(keywords):
    start_time = datetime.datetime.now()

    conn = pymysql.connect(host=xxxxxx', user='xxxx', password='xxxxx', db='xxxx', charset='utf8')
    try:
        with conn.cursor() as cursor:
            for keyword in keywords:
                count = 1                for x in range(1,1000,10):
                    now = datetime.datetime.now()
                    print(x)

                    url = 'https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query={0}&sm=tab_pge&srchby=all&st=sim&where=post&start={1}'.format(keyword,x)
                    response = requests.get(url,headers = headers)
                    html = BeautifulSoup(response.text,'html.parser')
                    bloghtmls = html.find_all('li',class_='sh_blog_top')
                    for bloghtml in bloghtmls:
                        print(count)
                        i = 0                        if 'title' in bloghtml.select('a')[1].attrs:
                            print(bloghtml.select('a')[1]['title'])  # 블로그 타이틀 -- a 태그중 2번째의 태그의  title 가 블로그 제목이다                            i = 1                        elif 'title' in bloghtml.select('a')[2].attrs:
                            print(bloghtml.select('a')[2]['title']) # 블로그 타이틀 -- a 태그중 2번째의 태그의  title 가 블로그 제목이다                            i = 2                        #print(bloghtml.select('a')[2]['title']) #블로그 타이틀 -- a 태그중 3번째의 태그의  title 가 블로그 제목이다                        print(bloghtml.select('a')[0]['href']) # URL -- a태그가 여러개라면 그중 첫번째 중에 href를 가져와라                        print(bloghtml.select('.txt84')[0].get_text()) #블로그명                        print(bloghtml.select('.txt_inline')[0].get_text()) #등록일자                        print('\n')

                        sql = """insert into naver_blog2(search_date, keyword, title, link,rank_b,write_date) values (%s, %s, %s, %s,%s,%s)"""                        cursor.execute(sql, (now,keyword,bloghtml.select('a')[i]['title'],bloghtml.select('a')[0]['href'],count,bloghtml.select('.txt_inline')[0].get_text()))
                        conn.commit()

                        count += 1

    finally:
        conn.close()
        end_time = datetime.datetime.now()
        run_time = end_time - start_time
        print(run_time)

blog_crawling(['python','c++','java'])

Continue reading

[python] pythonista 에서 모듈 설치, stash

모바일에서 파이썬 코딩하는 최고의 도구 pythonista 를 잘 사용하고 있다.
pythonista 에서 모듈을 설치하고 싶을 때 다음과 같은 방법을 통해 모듈을 설치 할 수 있다.

1. stash 를 설치한다.

  • https://github.com/ywangd/stash 에 installation 을 복사하여 pythonista에 추가
  • 즉 import requests as r; exec(r.get('https://bit.ly/get-stash').text) 를 복사하여 pythonista에서 실행
  • 실행 결과 ios에는 lunch_stash.py 가 실행되는데 이를 실행하면 프롬프트가 실행된다. 
  • pip install 모듈명 으로 원하는 모듈 설치

참고 

Continue reading

2019. 10. 8.

[MySQL] 외부에서 mysql에 접속하자

aws lambda 를 공부하다보면 외부에서 mysql에 접속해야 할 일이 있다. 그러기 위해 필요한 준비가 바로 '외부에서 나의 MySQL 서버로 접속하기' 이다.  그러면 이제 우리는 외부 접속용 계정을 만들고, 그 계정에 데이터베이스 접근 권한을 부여하고  서비스 재시작을 하면된다.

1. mysql 설정파일 수정(리눅스의 경우 /etc/my.cnf, 윈도우의 경우 my.ini)
필자는 windows 에 mysql을 설치했으므로 C:\ProgramData\MySQL\MySQL Server 8.0 폴더에서  my.ini를 수정한다.
  • bind-address=0.0.0.0 설정이 되어 있다면 주석처리하고, 그렇지 않다면 건너뛴다.
2. 원격에서 mysql에 접속 할 계정 생성
  • create user '계정명'@'호스트 명' identified by '암호';
  • 호스트명에는 모든 호스트를 허용할 경우 %, 로컬 호스트만 허용할 경우 localhost , 특정 IP를 허용할 경우 192.168.1.123 또는 192.168.% 라고 입력할 수 있다.
3. 권한 부여
  • grant all privileges on 데이터베이스명.* to '계정명'@'호스트명';
  • 모든 데이터베이스에 대한 접근을 허용할 경우 mydb 대신 * 를 넣어준다
4. 적용 확인 및 서비스 재시작
  • SELECT user, host from mysql.user;
  • 윈도우의 경우 서비스 메뉴에서 서비스 재시작을 하고 리눅스의 경우 sudo service mysql restart 또는 sudo systemctl restart mysql

Continue reading

Popular Posts

Recent Posts

Blog Archive

Powered by Blogger.