반응형

오늘은 저번에 올린 네이버 뉴스 크롤링(1)에서 한 단계 업그레이드된 뉴스 크롤러를 공유하려 합니다 :)

1편에서는 뉴스 1페이지만 크롤링을 할 수 있었는데요

2편에서는 여러 페이지를 크롤링 할 수 있는 코드를 구현하여 보았습니다!

반복적인 작업이 있는 부분을 함수로 만들고

그 함수의 객체를 만들어 구현하여 기사 제목, 본문을 가지고 올 수 있는 크롤러를 만들었습니다.

오늘의 포스팅은 코드 위주이니 코드가 왜 이렇게 나왔는지 자세한 설명이 필요하시다면 (1) 편을 확인해 주세요 :-)

 

step1. 크롤링 시 필요한 라이브러리 불러오기
#크롤링시 필요한 라이브러리 불러오기
from bs4 import BeautifulSoup
import requests

 

step 2. 반복적인 작업 함수화하기

반복적인 작업들을 def를 이용해 함수를 만들어 보겠습니다.

(1) 입력받은 페이지 url 형식에 맞추어 숫자를 바꿔주는 함수
# 페이지 url 형식에 맞게 바꾸어 주는 함수 만들기
  #입력된 수를 1, 11, 21, 31 ...만들어 주는 함수
def makePgNum(num):
    if num == 1:
        return num
    elif num == 0:
        return num+1
    else:
        return num+9*(num-1)
(2) Naver news url 생성하는 함수
# 크롤링할 url 생성하는 함수 만들기(검색어, 크롤링 시작 페이지, 크롤링 종료 페이지)
def makeUrl(search,start_pg,end_pg):
    if start_pg == end_pg:
        start_page = makePgNum(start_pg)
        url = "https://search.naver.com/search.naver?where=news&sm=tab_pge&query=" + search + "&start=" + str(start_page)
        print("생성url: ",url)
        return url
    else:
        urls= []
        for i in range(start_pg,end_pg+1):
            page = makePgNum(i)
            url = "https://search.naver.com/search.naver?where=news&sm=tab_pge&query=" + search + "&start=" + str(page)
            urls.append(url)
        print("생성url: ",urls)
        return urls
(3) html에서 원하는 속성 값 추출해주는 함수
# html에서 원하는 속성 추출하는 함수 만들기 (기사, 추출하려는 속성값)
def news_attrs_crawler(articles,attrs):
    attrs_content=[]
    for i in articles:
        attrs_content.append(i.attrs[attrs])
    return attrs_content
(4) 뉴스 기사 내용 크롤링하는 함수
#뉴스기사 내용 크롤링하는 함수 만들기(각 뉴스의 url)
def news_contents_crawler(news_url):
    contents=[]
    for i in news_url:
        #각 기사 html get하기
        news = requests.get(i)
        news_html = BeautifulSoup(news.text,"html.parser")
            #기사 내용 가져오기 (p태그의 내용 모두 가져오기) 
        contents.append(news_html.find_all('p'))
    return contents
(5) 뉴스기사 크롤러(main) 함수
#html생성해서 기사크롤링하는 함수 만들기(제목,url): 3개의 값을 반환함(제목, 링크, 내용)
def articles_crawler(url):
    #html 불러오기
    original_html = requests.get(i)
    html = BeautifulSoup(original_html.text, "html.parser")
    # 검색결과
    articles = html.select("div.group_news > ul.list_news > li div.news_area > a")
    title = news_attrs_crawler(articles,'title')
    url = news_attrs_crawler(articles,'href')
    content = news_contents_crawler(url)
    return title, url, content #3개의 값을 반환
step3. 함수를 이용하여 뉴스 크롤링 하기
#뉴스크롤링 시작

#검색어 입력
search = input("검색할 키워드를 입력해주세요:")

#검색 시작할 페이지 입력
page = int(input("\n크롤링할 시작 페이지를 입력해주세요. ex)1(숫자만입력):")) # ex)1 =1페이지,2=2페이지...
print("\n크롤링할 시작 페이지: ",page,"페이지")   
#검색 종료할 페이지 입력
page2 = int(input("\n크롤링할 종료 페이지를 입력해주세요. ex)1(숫자만입력):")) # ex)1 =1페이지,2=2페이지...
print("\n크롤링할 종료 페이지: ",page2,"페이지")   

# naver url 생성
url = makeUrl(search,page,page2)

#뉴스 크롤러 실행
news_titles = []
news_url =[]
news_contents =[]
for i in url:
    title, url,content = articles_crawler(url)
    news_titles.append(title)
    news_url.append(url)
    news_contents.append(content)

print("검색된 기사 갯수: 총 ",(page2+1-page)*10,'개')
print("\n[뉴스 제목]")
print(news_titles)
print("\n[뉴스 링크]")
print(news_url)
print("\n[뉴스 내용]")
print(news_contents)

[결과]

중략...

중략...

중략.....

이렇게 각각 뉴스 제목, 링크, 내용이 각각 출력됨을 확인 가능합니다 ㅎㅎ

크롤링할 페이지가 많을수록 시간이 오래 걸린 다는 점 참고해주세요 :)

step4. 데이터 프레임으로 만들기

이제 이 데이터들을 데이터 프레임으로 만들어 보도록 하겠습니다!

데이터 프레임으로 만들기 전에 내용을 보니 리스트가 [[]] 이런 식으로 중첩으로 되어서 저장되어 있기 때문에

한 개의 기사의 한 개의 제목, 링크, 내용을 할당하기 위해 for문을 사용하여 1차원리스트로 변경해 주겠습니다.

makeList라는 함수를 만들어 간편하게 변경해 주도록 하겠습니다.

###데이터 프레임으로 만들기###
import pandas as pd

#제목, 링크, 내용 1차원 리스트로 꺼내는 함수 생성
def makeList(newlist, content):
    for i in content:
        for j in i:
            newlist.append(j)
    return newlist
    
#제목, 링크, 내용 담을 리스트 생성
news_titles_1, news_url_1, news_contents_1 = [],[],[]

#1차원 리스트로 만들기(내용 제외)
makeList(news_titles_1,news_titles)
makeList(news_url_1,news_url)
makeList(news_contents_1,news_contents)


#데이터 프레임 만들기
news_df = pd.DataFrame({'title':news_titles_1,'link':news_url_1,'content':news_contents_1})
news_df

출력:

이런 식으로 데이터 프레임이 만들어졌습니다.

중간에 내용이 빈 칸은 사이트가 iframe으로 되어 있거나 할 것 같네요.

내용도 다 채우고 싶다면 한 사이트의 기사들만 추출하는 것이 깔끔합니다.

때문에 나는 더 깔끔하게 기사 내용을 추출하고 싶다! 하시는 분들은

1편의 내용을 참고하여 본인이 크롤링 하고 싶은 사이트만 전문으로 크롤링하는 코드를 만들어도 좋을 것 같습니다 .

전체 코드
#크롤링시 필요한 라이브러리 불러오기
from bs4 import BeautifulSoup
import requests

# 페이지 url 형식에 맞게 바꾸어 주는 함수 만들기
  #입력된 수를 1, 11, 21, 31 ...만들어 주는 함수
def makePgNum(num):
    if num == 1:
        return num
    elif num == 0:
        return num+1
    else:
        return num+9*(num-1)

# 크롤링할 url 생성하는 함수 만들기(검색어, 크롤링 시작 페이지, 크롤링 종료 페이지)
def makeUrl(search,start_pg,end_pg):
    if start_pg == end_pg:
        start_page = makePgNum(start_pg)
        url = "https://search.naver.com/search.naver?where=news&sm=tab_pge&query=" + search + "&start=" + str(start_page)
        print("생성url: ",url)
        return url
    else:
        urls= []
        for i in range(start_pg,end_pg+1):
            page = makePgNum(i)
            url = "https://search.naver.com/search.naver?where=news&sm=tab_pge&query=" + search + "&start=" + str(page)
            urls.append(url)
        print("생성url: ",urls)
        return urls

# html에서 원하는 속성 추출하는 함수 만들기 (기사, 추출하려는 속성값)
def news_attrs_crawler(articles,attrs):
    attrs_content=[]
    for i in articles:
        attrs_content.append(i.attrs[attrs])
    return attrs_content

#뉴스기사 내용 크롤링하는 함수 만들기(각 뉴스의 url)
def news_contents_crawler(news_url):
    contents=[]
    for i in news_url:
        #각 기사 html get하기
        news = requests.get(i)
        news_html = BeautifulSoup(news.text,"html.parser")
            #기사 내용 가져오기 (p태그의 내용 모두 가져오기) 
        contents.append(news_html.find_all('p'))
    return contents

#html생성해서 기사크롤링하는 함수 만들기(제목,url): 3개의 값을 반환함(제목, 링크, 내용)
def articles_crawler(url):
    #html 불러오기
    original_html = requests.get(i)
    html = BeautifulSoup(original_html.text, "html.parser")
    # 검색결과
    articles = html.select("div.group_news > ul.list_news > li div.news_area > a")
    title = news_attrs_crawler(articles,'title')
    url = news_attrs_crawler(articles,'href')
    content = news_contents_crawler(url)
    return title, url, content #3개의 값을 반환

#####뉴스크롤링 시작#####

#검색어 입력
search = input("검색할 키워드를 입력해주세요:")

#검색 시작할 페이지 입력
page = int(input("\n크롤링할 시작 페이지를 입력해주세요. ex)1(숫자만입력):")) # ex)1 =1페이지,2=2페이지...
print("\n크롤링할 시작 페이지: ",page,"페이지")   
#검색 종료할 페이지 입력
page2 = int(input("\n크롤링할 종료 페이지를 입력해주세요. ex)1(숫자만입력):")) # ex)1 =1페이지,2=2페이지...
print("\n크롤링할 종료 페이지: ",page2,"페이지")   

# naver url 생성
url = makeUrl(search,page,page2)

#뉴스 크롤러 실행
news_titles = []
news_url =[]
news_contents =[]
for i in url:
    title, url,content = articles_crawler(url)
    news_titles.append(title)
    news_url.append(url)
    news_contents.append(content)

print("검색된 기사 갯수: 총 ",(page2+1-page)*10,'개')
print("\n[뉴스 제목]")
print(news_titles)
print("\n[뉴스 링크]")
print(news_url)
print("\n[뉴스 내용]")
print(news_contents)

###데이터 프레임으로 만들기###
import pandas as pd

#제목, 링크, 내용 1차원 리스트로 꺼내는 함수 생성
def makeList(newlist, content):
    for i in content:
        for j in i:
            newlist.append(j)
    return newlist
    
#제목, 링크, 내용 담을 리스트 생성
news_titles_1, news_url_1, news_contents_1 = [],[],[]

#1차원 리스트로 만들기(내용 제외)
makeList(news_titles_1,news_titles)
makeList(news_url_1,news_url)
makeList(news_contents_1,news_contents)


#데이터 프레임 만들기
news_df = pd.DataFrame({'title':news_titles_1,'link':news_url_1,'content':news_contents_1})
news_df

 

코드 파일

naver_news_crawler.ver1.0.ipynb
0.98MB

마무리

1편에서 좀 더 업그레이드된 크롤러를 만들어 보았는데요

궁금한 사항이나 크롤러 업그레이드에 대한 좋은 의견이 있으시다면

댓글 남겨주세요 ^o^

제 코드가 도움이 되길 바랍니다.ㅎㅎ

 

+ 최신 버전을 확인하고 싶다면??

https://wonhwa.tistory.com/46?category=996518

 

[python] 원하는 검색어로 네이버 뉴스 기사 제목 및 내용만 크롤링하기

안녕하세요! 크롤링 포스팅을 오랜만에 진행하네요~ 이번에는 네이버 뉴스 검색 결과중 네이버 뉴스에 기사가 있는 링크들만 가져와 크롤링을 진행해 보도록 하겠습니다. 지난 크롤러에서 아쉬

wonhwa.tistory.com

위의 게시물을 방문해 주세요:)

반응형

+ Recent posts