Skip to content

Instantly share code, notes, and snippets.

@dongsam
Last active July 10, 2017 15:29
Show Gist options
  • Save dongsam/55a0f00d4eab9185c55a to your computer and use it in GitHub Desktop.
Save dongsam/55a0f00d4eab9185c55a to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# (놀러온특강) Python을 통한 웹 스크래핑 및 DB화 \n",
"\n",
"## 발표자 : 변동삼\n",
"\n",
"### Python Backend 개발자\n",
"- Django, Flask\n",
"- 현재 여의도 모 핀테크 회사에서 \n",
" \n",
"### 관심 분야\n",
"- Fintech\n",
"- Data Engineering\n",
"- NLP\n",
" \n",
"### Crawling, Scraping\n",
"- 여행사, 쇼핑몰 상품, 게시판, 실시간 크롤링 및 DB저장 자동화\n",
"- 날씨, 뉴스, 시청률, SNS, 스포츠 경기 등 다수 크롤링 자동화\n",
"- 토렌트 사이트 토렌트 및 이미지 크롤링 및 DB화, 업로드 자동화\n",
"- 부동산, 숙박업소 정보 크롤링 및 DB화\n",
"- 중고거래 사이트 크롤링, 자동화\n",
"- iOS, 안드로이드 어플 분석 및 어플을 통해 제공되는 데이터 크롤링\n",
"- 트위터, 페이스북, 인스타그램 크롤링 및 자동 포스팅\n",
"- [뉴스 크롤링 기반 주식 자동매매 (시스템 트레이딩) - 이트레이드 증권 Xing API](https://youtu.be/1RQs_1gU19w)\n",
"- 선관위, 정치 뉴스 크롤링 및 선거 트렌드 예측\n",
"- 한글 사전 크롤링 및 유의어, 반의어 사전 구축\n",
"- N사 사이트, 지도 검색 결과 크롤링 \n",
"- 셀레니엄(selenium) 을 통한 브라우저 자동화 및 웹서핑, 데이터수집 자동화"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## 크롤링 예제 대상\n",
"\n",
"### 상장사 리스트\n",
"- http://finance.daum.net/quote/all.daum?type=S&stype=P\n",
"- ![duam_lit](http://i.imgur.com/7DLMoST.png)\n",
"- bs4 사용 방법 소개\n",
"- HTML\n",
" \n",
"### 네이버 증권 종목분석\n",
"- 네이버 금융에서 제공되는 코스피, 코스닥 상장사들의 재무재표, 주식 메타데이터(Financial Summary) 데이터 \n",
"- ex) [SK하이닉스](http://finance.naver.com/item/coinfo.nhn?code=000660)\n",
"- ![naver_stock](http://i.imgur.com/7jaAVAx.png)\n",
"- 비동기 데이터 (ajax)\n",
"- source : data_crawler/naver_stock_meta_info/crawler.py\n",
"- 저장 : mysql\n",
" \n",
"### 네이버 증권 종목토론\n",
"- 네이버 금융의 각 종목별 종목 토론실 게시판의 날짜, 제목, 투자의견, 글쓴이, 조회, 공감, 비공감, 내용 등 수집\n",
"- 투자의견( 의견없음 매수, 강력매수, 매도, 강력매도, 중립 ) 을 라벨로서 기반하여 제목, 내용에 나타나는 단어를 분석하여 긍, 부정 단어를 확보하기 위한 학습용 데이터로 활용 가능 \n",
"- ![naver_discussion](http://i.imgur.com/EpocU5n.png)\n",
"- source : data_crawler/naver_stock_discussion/crawler.py\n",
"- 저장 : mongodb\n",
"\n",
"### 네이버 증권 실시간 데이터\n",
"- 장 마감 이후에도 실시간 데이터가 온다면 라이브 코딩"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## 오늘 예제에서 사용되는 Tool, Library\n",
"\n",
"- Chrome Developer Tools (개발자도구)\n",
"- BeautifulSoup4\n",
" - Python 에서 HTML 구조 분석, 객체화하는 Library\n",
" - `pip install BeautifulSoup4`\n",
" - ```import bs4```\n",
" \n",
"- requests\n",
"- gevent\n",
"- http://curl.trillworks.com/\n",
"- har2requests\n",
"- crawlib\n",
" - https://github.com/dongsam/crawlib\n",
"- pymysql\n",
"- pymongo"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 상장사 리스트\n",
"- http://finance.daum.net/quote/all.daum?type=S&stype=P\n",
"- ![duam_lit](http://i.imgur.com/7DLMoST.png)\n",
"- bs4 사용 방법 소개\n",
"- HTML"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import urllib2\n",
"import bs4"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"url = 'http://finance.daum.net/quote/all.daum?type=S&stype=P'\n",
"html = urllib2.urlopen(url).read()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"384272"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(html)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<!doctype html public \"-//w3c//dtd html 4.01 transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\t\n",
"\t\t\t\t<html lang=\"ko\">\n",
"<head>\n",
"\t<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n",
"<meta http-equiv=\"X-UA-Compatible\" content=\"IE=10\" />\n",
"<title>전종목 시세 - Daum 금융</title>\n",
"<meta name=\"verify-v1\" content=\"iXgHW7UooMcyeiV/Zb0Tk/yK2yB+IuA5/5GgIzGBEns=\" >\n",
"<meta property=\"og:image\" content=\"http://i1.daumcdn.net/img-media/mobile/meta/finance.png\"/>\n",
"<link rel=\"stylesheet\" href=\"http://s1.daumcdn.net/stock/css/common.css?ver=20160220214249\" type=\"text/css\">\n",
"<link rel=\"stylesheet\" href=\"http://s1.daumcdn.net/stock/css/newHeader.css?ver=20160220214249\" type=\"text/css\">\n",
"<link rel=\"stylesheet\" href=\"http://s1.daumcdn.net/stock/css/column.css?ver=20160220214249\" type=\"text/css\">\n",
"<link rel=\"stylesheet\" href=\"http://s1.daumcdn.net/stock/css/trade.css?ver=20160220214249\" type=\"text/css\">\n",
"<script type=\"text/javascript\" src=\"http://s1.daumcdn.net/stock/js/common.js?ve\n"
]
}
],
"source": [
"print html[:1000]"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"soup = bs4.BeautifulSoup(html)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<title>전종목 시세 - Daum 금융</title>\n",
"전종목 시세 - Daum 금융\n"
]
}
],
"source": [
"title = soup.find('title')\n",
"print title\n",
"print title.text"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![duam_1](http://i.imgur.com/wibLFPd.png)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1724\n",
"571\n"
]
}
],
"source": [
"print len(soup.find_all('td'))\n",
"print len(soup.find_all('td','txt'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 기업 개수 미달, HTML파일을 끝까지 파싱하지 못한 상황\n",
"- BeautfulSoup 함수호출시 파서를 'html.parser' 로 지정해줌으로서 해결가능"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3580\n",
"1189\n"
]
}
],
"source": [
"soup = bs4.BeautifulSoup(html, 'html.parser')\n",
"print len(soup.find_all('td'))\n",
"print len(soup.find_all('td','txt'))"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"able KQ Monthly Best 11 ETN\n",
"able Monthly Best 11 ETN\n",
"able Quant비중조절 ETN\n",
"able 우량주 Monthly Best 11 ETN\n",
"able 코스피200선물플러스 ETN\n",
"AJ네트웍스\n",
"AJ렌터카\n",
"AK홀딩스\n",
"ARIRANG 200\n",
"ARIRANG AC 월드(합성 H)\n",
"ARIRANG K100EW\n",
"ARIRANG KOSPI50\n",
"ARIRANG S&P; 배당성장\n",
"ARIRANG 고배당주\n",
"ARIRANG 단기유동성\n",
"ARIRANG 미국고배당주(합성 H)\n",
"ARIRANG 바벨 채권\n",
"ARIRANG 방어주\n",
"ARIRANG 선진국(합성 H)\n",
"ARIRANG 스마트베타 LowVOL\n"
]
}
],
"source": [
"for i in soup.find_all('td','txt')[:20]:\n",
" print i.text"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### URL에서 code 추출"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"able KQ Monthly Best 11 ETN /item/main.daum?code=580004\n",
"able Monthly Best 11 ETN /item/main.daum?code=580003\n",
"able Quant비중조절 ETN /item/main.daum?code=580002\n",
"able 우량주 Monthly Best 11 ETN /item/main.daum?code=580005\n",
"able 코스피200선물플러스 ETN /item/main.daum?code=580001\n",
"AJ네트웍스 /item/main.daum?code=095570\n",
"AJ렌터카 /item/main.daum?code=068400\n",
"AK홀딩스 /item/main.daum?code=006840\n",
"ARIRANG 200 /item/main.daum?code=152100\n",
"ARIRANG AC 월드(합성 H) /item/main.daum?code=189400\n",
"ARIRANG K100EW /item/main.daum?code=141240\n",
"ARIRANG KOSPI50 /item/main.daum?code=122090\n",
"ARIRANG S&P; 배당성장 /item/main.daum?code=222170\n",
"ARIRANG 고배당주 /item/main.daum?code=161510\n",
"ARIRANG 단기유동성 /item/main.daum?code=190160\n",
"ARIRANG 미국고배당주(합성 H) /item/main.daum?code=213630\n",
"ARIRANG 바벨 채권 /item/main.daum?code=190150\n",
"ARIRANG 방어주 /item/main.daum?code=161490\n",
"ARIRANG 선진국(합성 H) /item/main.daum?code=195970\n",
"ARIRANG 스마트베타 LowVOL /item/main.daum?code=236460\n"
]
}
],
"source": [
"for i in soup.find_all('td','txt')[:20]:\n",
" print i.text, i.a['href']"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"company_dic = {}\n",
"for i in soup.find_all('td','txt'):\n",
" company_dic[i.text] = i.a['href'].split('=')[1]"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1189\n"
]
},
{
"data": {
"text/plain": [
"u'006840'"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print len(company_dic)\n",
"company_dic[u'AK홀딩스']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 위 과정 함수화시켜 kosdaq도 간편히 가져와보기 "
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def get_company_list(url):\n",
" soup = bs4.BeautifulSoup(urllib2.urlopen(url).read(),'html.parser')\n",
" company_dic = {}\n",
" for i in soup.find_all('td','txt'):\n",
" company_dic[i.text] = i.a['href'].split('=')[1]\n",
" return company_dic"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"이테크건설 016250\n",
"해덕파워웨이 102210\n",
"산성앨엔에스 016100\n",
"엔에이치스팩5호 215790\n",
"서부T&D; 006730\n",
"이스트아시아홀딩스 900110\n",
"웰크론 065950\n",
"아이리버 060570\n",
"대주산업 003310\n",
"우리이티아이 082850\n",
"흥국에프엔비 189980\n",
"CS 065770\n",
"시그네틱스 033170\n",
"성우전자 081580\n",
"신진에스엠 138070\n",
"바이오스마트 038460\n",
"동양이엔피 079960\n",
"심엔터테인먼트 204630\n",
"피제이메탈 128660\n",
"한창산업 079170\n"
]
}
],
"source": [
"kospi_url = 'http://finance.daum.net/quote/all.daum?type=U&stype=P'\n",
"kosdaq_url = 'http://finance.daum.net/quote/all.daum?type=U&stype=Q'\n",
"\n",
"kosdaq_dic = get_company_list(kosdaq_url)\n",
"for k, v in kosdaq_dic.items()[:20]:\n",
" print k, v"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### pymysql 을 이용한 mysql 세팅 및 db insert(replace)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import pymysql # pip install pymysql\n",
"mysql_host = \"127.0.0.1\"\n",
"mysql_user = \"root\"\n",
"mysql_passwd = \"mysql\"\n",
"mysql_db = \"stock\"\n",
"mysql_port = 3306\n",
"conn = pymysql.connect(host=mysql_host, user=mysql_user, passwd=mysql_passwd, db=mysql_db, port=mysql_port, charset='utf8')\n",
"conn.autocommit(True)\n",
"cur = conn.cursor()\n",
"\n",
"'''\n",
"CREATE TABLE `COMPANY2` (\n",
" `company_id` varchar(11) NOT NULL DEFAULT '',\n",
" `company_name` varchar(255) DEFAULT '',\n",
" `company_type` tinyint(10) DEFAULT NULL,\n",
" PRIMARY KEY (`company_id`)\n",
") ENGINE=InnoDB DEFAULT CHARSET=utf8;\n",
"'''\n",
"\n",
"for k,v in kosdaq_dic.items():\n",
" cur.execute(\"replace into COMPANY2 (company_id, company_name, company_type ) values ('{}', '{}', '{}')\".format( v.encode('utf-8'), k.encode('utf-8'), 0 ))\n",
"\n",
"for k,v in company_dic.items():\n",
" cur.execute(\"replace into COMPANY2 (company_id, company_name, company_type ) values ('{}', '{}', '{}')\".format( v.encode('utf-8'), k.encode('utf-8'), 1 ))"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false,
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"000020 동화약품 1\n",
"000030 우리은행 1\n",
"000040 KR모터스 1\n",
"000050 경방 1\n",
"000060 메리츠화재 1\n",
"000070 삼양홀딩스 1\n",
"000075 삼양홀딩스우 1\n",
"000080 하이트진로 1\n",
"000087 하이트진로2우B 1\n",
"000100 유한양행 1\n"
]
}
],
"source": [
"cur.execute(\"\"\"select * from COMPANY2\"\"\")\n",
"cur_tmp = cur.fetchall()\n",
"for i in cur_tmp[:10]:\n",
" print i[0], i[1], i[2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 네이버 증권 종목분석\n",
"- 네이버 금융에서 제공되는 코스피, 코스닥 상장사들의 재무재표, 주식 메타데이터(Financial Summary) 데이터 \n",
"- ex) [SK하이닉스](http://finance.naver.com/item/coinfo.nhn?code=000660)\n",
"- ![naver_stock](http://i.imgur.com/7jaAVAx.png)\n",
"- 비동기 데이터 (ajax)\n",
"- source : data_crawler/naver_stock_meta_info/crawler.py\n",
"- 저장 : mysql"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import requests\n",
"import urllib\n",
"import bs4\n",
"import json\n",
"import re\n",
"import crawlib\n",
"import datetime\n",
"import sys\n",
"import crawlib\n",
"import pymysql # pip install pymysql"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"mysql_host = \"127.0.0.1\"\n",
"mysql_user = \"root\"\n",
"mysql_passwd = \"mysql\"\n",
"mysql_db = \"stock\"\n",
"mysql_port = 3306\n",
"conn = pymysql.connect(host=mysql_host, user=mysql_user, passwd=mysql_passwd, db=mysql_db, port=mysql_port, charset='utf8')\n",
"conn.autocommit(True)\n",
"cur = conn.cursor()"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def extract_table(html):\n",
" soup = bs4.BeautifulSoup(html)\n",
" th = soup.find_all(\"th\",\"title\")\n",
" vertical_columns = [i.text.strip() for i in th]\n",
"\n",
" bg = soup.find_all(\"th\",re.compile(r\"^r\"))[2:]\n",
" horizon_columns = [crawlib.getOnlyDigit(i.text.strip()) for i in bg]\n",
"\n",
" cBk = [int(crawlib.getOnlyDigit(i.text)) for i in soup.find_all(\"td\",\"num\")]\n",
"\n",
" # colums_count_check\n",
" if len(cBk) != (len(vertical_columns) * len(horizon_columns)):\n",
" print(error)\n",
" sys.exit()\n",
" \n",
" return vertical_columns, horizon_columns, cBk\n",
"\n",
"\n",
"def request_and_store(company_code, freq_typ, fin_typ=0):\n",
" company_code = str(company_code).zfill(6)\n",
" # zero padding 6\n",
" url = 'http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd={}&fin_typ={}&freq_typ={}'.format(company_code, str(fin_typ), freq_typ)\n",
" print url\n",
" headers = {\n",
" 'Accept-Language' : 'ko-KR,ko;q=0.8,en-US;q=0.6,en;q=0.4',\n",
" 'Accept-Encoding' : 'gzip, deflate, sdch',\n",
" 'X-Requested-With' : 'XMLHttpRequest',\n",
" 'Connection' : 'keep-alive',\n",
" 'Accept' : 'text/html, */*; q=0.01',\n",
" 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36',\n",
" 'Host' : 'companyinfo.stock.naver.com',\n",
" }\n",
" cookies = {\n",
" }\n",
" data_dic = {\n",
" # 'freq_typ' : '''Y''',\n",
" # 'fin_typ' : '''0''',\n",
" # 'cmp_cd' : '''051910''',\n",
" }\n",
" data = \"\"\n",
" for k, v in data_dic.items():\n",
" data += urllib.quote_plus(k)+\"=\"+urllib.quote_plus(v)+\"&\"\n",
" res = requests.post(url, headers=headers, cookies=cookies, data=data)\n",
" vertical_columns, horizon_columns, cBk = extract_table(res.content)\n",
"\n",
" cnt = 0\n",
" print len(cBk)\n",
" for value in cBk:\n",
" vertical_i = cnt / len(horizon_columns)\n",
" horizon_i = cnt % len(horizon_columns)\n",
"# print vertical_columns[vertical_i], horizon_columns[horizon_i]\n",
"# print value\n",
" try:\n",
" cur.execute(\"\"\"replace into META (company_id, meta_type, meta_freq_type, meta_value, meta_date, meta_crawled_date ) values ('{}', '{}', '{}', '{}', '{}', '{}')\"\"\".format( \n",
" company_code, vertical_columns[vertical_i].encode(\"utf-8\"), freq_typ , value, datetime.datetime.strptime(horizon_columns[horizon_i],\"%Y%m\"), datetime.datetime.now())\n",
" )\n",
" except Exception as e:\n",
" print e\n",
" cnt += 1\n",
" print cnt"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false,
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd=000020&fin_typ=0&freq_typ=Q\n",
"256\n",
"256\n",
"http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd=000020&fin_typ=0&freq_typ=Y\n",
"256\n",
"256\n",
"http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd=000030&fin_typ=0&freq_typ=Q\n",
"256\n",
"256\n",
"http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd=000030&fin_typ=0&freq_typ=Y\n",
"256\n",
"256\n",
"http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd=000040&fin_typ=0&freq_typ=Q\n",
"256\n",
"256\n",
"http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd=000040&fin_typ=0&freq_typ=Y\n",
"256\n",
"256\n"
]
}
],
"source": [
"cur.execute(\"\"\"select * from COMPANY2\"\"\")\n",
"cur_tmp = cur.fetchall()\n",
"for i in cur_tmp[:3]:\n",
" request_and_store(i[0],'Q')\n",
" request_and_store(i[0],'Y')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 주기적 실행, 자동화\n",
"- cron ( crontab )\n",
"- [supervisor](http://supervisord.org/)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 네이버 증권 종목토론\n",
"- 네이버 금융의 각 종목별 종목 토론실 게시판의 날짜, 제목, 투자의견, 글쓴이, 조회, 공감, 비공감, 내용 등 수집\n",
"- 투자의견( 의견없음 매수, 강력매수, 매도, 강력매도, 중립 ) 을 라벨로서 기반하여 제목, 내용에 나타나는 단어를 분석하여 긍, 부정 단어를 확보하기 위한 학습용 데이터로 활용 가능 \n",
"- ![naver_discussion](http://i.imgur.com/EpocU5n.png)\n",
"- source : data_crawler/naver_stock_discussion/crawler.py\n",
"- 저장 : mongodb"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import logging\n",
"import pymongo\n",
"import crawlib\n",
"import time\n",
"from datetime import datetime\n",
"from gevent import monkey\n",
"monkey.patch_all()\n",
"from gevent.pool import Pool\n",
"\n",
"collection = pymongo.MongoClient().stock.naver_discussion\n"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class NaverCrawling(crawlib.Crawling):\n",
" def get_item_list(self, cate, page):\n",
" url = self.make_target_url(cate, page)\n",
" soup = crawlib.getSoup(url)\n",
" link_list = []\n",
" for i in soup.find_all('tr',{'onmouseover':'mouseOver(this)'}):\n",
" link = i.find_all('td')[1].a['href'].split('&st=&sw=&page')[0]\n",
" link = crawlib.urljoin('http://finance.naver.com',link)\n",
"\n",
" # already exist this data\n",
" if self.data_dic.has_key(link):\n",
" print \"exist\", link\n",
" continue\n",
"\n",
" self.data_dic[link] = {}\n",
" self.data_dic[link]['date'] = i.find_all('td')[0].text.strip()\n",
" self.data_dic[link]['title'] = i.find_all('td')[1].a['title'].strip()\n",
" self.data_dic[link]['opinion'] = i.find_all('td')[2].text.strip()\n",
" self.data_dic[link]['view'] = i.find_all('td')[4].text.strip()\n",
" self.data_dic[link]['sympathy'] = i.find_all('td')[5].text.strip()\n",
" self.data_dic[link]['unsympathy'] = i.find_all('td')[6].text.strip()\n",
" self.data_dic[link]['_id'] = link\n",
"\n",
" link_list.append(link)\n",
" # self.get_item(link)\n",
"\n",
" if len(link_list) == 0:\n",
" return 'stop'\n",
"\n",
" pool = Pool(len(link_list))\n",
" res = pool.map(self.get_item, link_list)\n",
"\n",
" def get_item(self, url, key=''):\n",
" if not key:\n",
" key = url\n",
" soup = crawlib.getSoup(url)\n",
" content = '\\n'.join([i.text for i in soup.find_all('div','view_se')]).strip()\n",
" user = soup.find('th','info').find('span').text.strip()\n",
" nid = crawlib.get_param_from_url(url, 'nid')\n",
" code = crawlib.get_param_from_url(url, 'code')\n",
"\n",
" self.data_dic[key]['content'] = content\n",
" self.data_dic[key]['nid'] = nid\n",
" self.data_dic[key]['code'] = code\n",
" self.data_dic[key]['user'] = user\n",
"\n",
" print key, self.data_dic[key]['opinion']\n",
" # runtime_check = time.time()\n",
" collection.replace_one({\"_id\": key}, self.data_dic[key], upsert=True)\n",
" # print time.time() - runtime_check\n",
"\n",
"\n",
" # todo: mongo db library 화\n",
" # todo: 최신글부터 가져오되 몇개이상(한페이지이상) 중복 감지시 stop\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"target_name = 'naver_stock_discussion'\n",
"naver_dicussion = NaverCrawling(target_name=target_name, base_url='http://finance.naver.com/item/board.nhn?', cate_param='code',\n",
" page_param='page', cate_list_path='category.txt', page_list=range(1, 1000))\n",
"\n",
"\n",
"naver_dicussion.crawling_cate_list(cate_delay=0, page_delay=0)\n",
"# 결과는 console 에서 확인 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 네이버 증권 실시간 데이터\n",
"- 장 마감 이후에도 실시간 데이터가 온다면 라이브 코딩\n",
"- http://finance.naver.com/item/main.nhn?code=035420\n",
"- live coding youtube 영상 : https://youtu.be/2UP91K7SUzE"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import crawlib # https://github.com/dongsam/crawlib"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"res = crawlib.har2requests('finance.naver.com.har') # 각자 크롬 개발자도구통해 받은 har 파일 경로 입력 "
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# print res # 아래 코드 생성"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{u'result': {u'areas': [{u'datas': [{u'aa': 37807000000,\n",
" u'aq': 59460,\n",
" u'cd': u'035420',\n",
" u'cnsPer': 31.27,\n",
" u'cr': 0.47,\n",
" u'cv': 3000,\n",
" u'hv': 642000,\n",
" u'll': 446000,\n",
" u'lv': 630000,\n",
" u'ms': u'CLOSE',\n",
" u'mt': u'1',\n",
" u'nav': None,\n",
" u'nm': u'NAVER',\n",
" u'nv': 639000,\n",
" u'ov': 633000,\n",
" u'pbr': 8.78,\n",
" u'pcv': 636000,\n",
" u'per': 40.6,\n",
" u'rf': u'2',\n",
" u'sv': 636000,\n",
" u'tyn': u'N',\n",
" u'ul': 826000}],\n",
" u'name': u'SERVICE_RECENT_ITEM'},\n",
" {u'datas': [{u'aa': 37807000000,\n",
" u'aq': 59460,\n",
" u'cd': u'035420',\n",
" u'cnsPer': 31.27,\n",
" u'cr': 0.47,\n",
" u'cv': 3000,\n",
" u'hv': 642000,\n",
" u'll': 446000,\n",
" u'lv': 630000,\n",
" u'ms': u'CLOSE',\n",
" u'mt': u'1',\n",
" u'nav': None,\n",
" u'nm': u'NAVER',\n",
" u'nv': 639000,\n",
" u'ov': 633000,\n",
" u'pbr': 8.78,\n",
" u'pcv': 636000,\n",
" u'per': 40.6,\n",
" u'rf': u'2',\n",
" u'sv': 636000,\n",
" u'tyn': u'N',\n",
" u'ul': 826000}],\n",
" u'name': u'SERVICE_ITEM'}],\n",
" u'pollingInterval': 60000,\n",
" u'time': 1458441607440},\n",
" u'resultCode': u'success'}\n"
]
}
],
"source": [
"import requests\n",
"import urllib\n",
"import json\n",
"from pprint import pprint\n",
"url = 'http://polling.finance.naver.com/api/realtime.nhn?query=SERVICE_ITEM:035420|SERVICE_RECENT_ITEM:035420&_callback='\n",
"headers = {\n",
" 'Accept-Language' : 'ko-KR,ko;q=0.8,en-US;q=0.6,en;q=0.4',\n",
" 'Accept-Encoding' : 'gzip, deflate, sdch',\n",
" 'Connection' : 'keep-alive',\n",
" 'Accept' : '*/*',\n",
" 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36',\n",
" 'Host' : 'polling.finance.naver.com',\n",
" 'Referer' : 'http://finance.naver.com/item/main.nhn?code=035420',\n",
"}\n",
"cookies = {\n",
"}\n",
"data_dic = {\n",
"}\n",
"data = \"\"\n",
"for k, v in data_dic.items():\n",
" data += urllib.quote_plus(k)+\"=\"+urllib.quote_plus(v)+\"&\"\n",
"res = requests.post(url, headers=headers, cookies=cookies, data=data)\n",
"res_str = res.content.decode('euc-kr').encode('utf-8')\n",
"res_json = json.loads(res_str)\n",
"pprint(res_json)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.9"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
@dongsam
Copy link
Author

dongsam commented Jun 21, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment