Today I Learned/Python & Pandas

[Python] News Crawling

하나719 2020. 10. 20. 22:51
반응형
python_news_crawling

데잇걸즈 파이썬 톺아보기 과제로 진행했습니다.

과제. BeautifulSoup을 이용하여 아래의 세 기사의 제목과 언론사를 크롤링해주세요!

  • for문을 이용하여 url 각각의 기사제목과 언론사를 가져와주세요
  • 가져온 정보를 아래와 같이 DataFrame으로 만들어 주세요
title company url
13일부터 마스크 착용 의무화..한 달 계도 후 과태료 10만 원 YTN https://news.v.daum.net/v/20201004215700006
"사망 10대와 같은 곳서 같은 백신 접종한 32명, 이상반응 없어" 연합뉴스 https://news.v.daum.net/v/20201020153505519
지하수에 사는 '골룸 가물치'야, 넌 어디서 왔니 한겨레 https://news.v.daum.net/v/20201020153609574
In [46]:
crawl_url = ["https://news.v.daum.net/v/20201004215700006", "https://news.v.daum.net/v/20201020153505519", "https://news.v.daum.net/v/20201020153609574"]

import library

In [53]:
import requests
from bs4 import BeautifulSoup as bs
import pandas as pd

데이터 읽어오기

  • requests.get(): 서버에 데이터 요청해서 가져오기
  • bs(res.content,'html.parser'): BeautifulSoup으로 깔끔하게 바꿔주기
In [8]:
res = requests.get("https://news.v.daum.net/v/20201004215700006")
In [9]:
soup = bs(res.content, 'html.parser')

BeautifulSoup의 메서드 활용해서 원하는 데이터 뽑기

1) 기사 타이틀 가져오기

  • find(태그명)
  • 위에 방법 안되면 select
In [44]:
# find(태그명): title 태그 잘 사용했으니, select로 따로 부르지 않아도 된다.(다행)
soup.find('title').text
Out[44]:
'13일부터 마스크 착용 의무화..한 달 계도 후 과태료 10만 원'
In [ ]:
 

2) 언론사 이름 가져오기

기사 끝나는 하단에 (언론사 이름) 주요 뉴스 섹션이 있다.

이 부분을 검사해서 가져와보자

-> 문장으로 출력돼서 후 가공 필요하다.

In [14]:
# copy selector 로 가져옴
soup.select('#mArticle > div.foot_view > div.cp_view > strong')
Out[14]:
[<strong class="tit_cp">YTN 주요 뉴스<span class="info_cp">해당 언론사로 연결됩니다.</span></strong>]
In [20]:
# 클래스 명으로 가져옴
soup.select('.tit_cp')[0].text
Out[20]:
'YTN 주요 뉴스해당 언론사로 연결됩니다.'

기사 타이틀 위에 회사 로고 이미지에 alt속성 값으로 회사명이 들어있다.

img 태그의 alt 속성값을 가져오자

In [34]:
#find_all(태그명)은 리스트로 값을 반환하기때문에 for문 in 뒤에 바로 써 줄 수 있다.
#alt = True 파라미터로 alt값이 있는 태그만 가져올 수 있다. 
for i in soup.find_all('img',alt=True):
    print(i['alt'])
Daum
YTN
In [43]:
#위에 for문에서 1번째 인덱스에 있는것 확인
soup.find_all('img',alt=True)[1]['alt']
Out[43]:
'YTN'

함수 만들기

3개의 기사가 같은 플랫폼이기 때문에, 구조가 같을거라고 가정하고 url을 전달하면 원하는 데이터를 출력해주는 함수를 만들어보자

In [70]:
# title 
def get_title(url):
    res = requests.get(url)
    soup = bs(res.content, 'html.parser')
    title=soup.find('title').text
    return title
In [71]:
# company
def get_company(url):
    res = requests.get(url)
    soup = bs(res.content, 'html.parser')
    company=soup.find_all('img',alt=True)[1]['alt']
    return company
In [76]:
title = []
company = []

for url in crawl_url:
    # 함수에서 크롤링 실행
    t = get_title(url)
    c = get_company(url)
    
    # 얻어온 값 리스트에 추가 (데이터프레임에 넣기위해)
    title.append(t)
    company.append(c)
In [77]:
# 데이터프레임 생성
df=pd.DataFrame({
    'title':title,
    'company':company,
    'url':crawl_url
    })
df
Out[77]:
title company url
0 13일부터 마스크 착용 의무화..한 달 계도 후 과태료 10만 원 YTN https://news.v.daum.net/v/20201004215700006
1 "사망 10대와 같은 곳서 같은 백신 접종한 32명, 이상반응 없어" 연합뉴스 https://news.v.daum.net/v/20201020153505519
2 지하수에 사는 '골룸 가물치'야, 넌 어디서 왔니 한겨레 https://news.v.daum.net/v/20201020153609574

함수 합치기

  • 중복 된 부분 줄여주자
  • python 함수에서 두개의 값을 동시에 튜플로 반환할 수 있음
In [80]:
# title 
def get_title_company(url):
    res = requests.get(url)
    soup = bs(res.content, 'html.parser')
    title=soup.find('title').text
    company=soup.find_all('img',alt=True)[1]['alt']
    return title,company
In [88]:
title = []
company = []

for url in crawl_url:
    # 함수에서 크롤링 실행
    # 튜플로 리턴된 값을 각각 gt, gc 변수에 넣어준다.
    gt, gc = get_title_company(url)

    # 얻어온 값 리스트에 추가 (데이터프레임에 넣기위해)
    title.append(gt)
    company.append(gc)
In [89]:
title
Out[89]:
['13일부터 마스크 착용 의무화..한 달 계도 후 과태료 10만 원',
 '"사망 10대와 같은 곳서 같은 백신 접종한 32명, 이상반응 없어"',
 "지하수에 사는 '골룸 가물치'야, 넌 어디서 왔니"]
In [90]:
company
Out[90]:
['YTN', '연합뉴스', '한겨레']
In [91]:
# 데이터프레임 생성
df=pd.DataFrame({
    'title':title,
    'company':company,
    'url':crawl_url
    })
df
Out[91]:
title company url
0 13일부터 마스크 착용 의무화..한 달 계도 후 과태료 10만 원 YTN https://news.v.daum.net/v/20201004215700006
1 "사망 10대와 같은 곳서 같은 백신 접종한 32명, 이상반응 없어" 연합뉴스 https://news.v.daum.net/v/20201020153505519
2 지하수에 사는 '골룸 가물치'야, 넌 어디서 왔니 한겨레 https://news.v.daum.net/v/20201020153609574
In [ ]:
 
In [93]:
from IPython.core.display import display, HTML
display(HTML("<style>.container {width:90% !important;}</style>"))
In [ ]:
 
반응형