-->

[파이썬] 네이버 플레이스, 맛집 (JSON 데이터) 크롤링 (2)

반응형

+) 제가 크롤링에 사용한 URL 서비스 자체(store.naver.com)가 중단되고 새롭게 개편된 것으로 확인됩니다. 따라서 아래 코드에 사용된 URL로는 현재 크롤링이 불가하니 JSON 응답값을 주는 사이트의 크롤링 코드 작성 방법, 방식 위주로만 확인 부탁드립니다!

 

 

저번 포스팅에서 서울시의 구/동 별로 카테고리를 나누어 크롤링하기 위해 서울시 행정구역 정보를 저장했고, 크롤링 URL을 구성하기 위한 작업을 선행했다. 그리고 해당 URL 요청을 통해 응답을 받았고 응답 코드 500이 나오는 경우에 대한 처리까지 마쳤다. 

 

이번 포스팅에서는 저번 내용에 이어서, 응답으로 받은 값을 파이썬 json 모듈을 사용해 파싱하고 저장하는 코드를 작성해보자. 이전 포스팅에서 내용과 코드가 모두 이어지므로 필요한 사람은 이전 포스팅을 확인하거나 포스팅 하단부의 전체코드를 확인하길 바란다.

 

/* 추가적으로 크롤링 중간에 막히는 문제가 해결되었습니다 */

 


이전포스팅

2020/06/12 - [프로그래밍/파이썬] - [파이썬] 네이버 플레이스, 맛집 (JSON 데이터) 크롤링 (1)

 

[파이썬] 네이버 플레이스, 맛집 (JSON 데이터) 크롤링 (1)

빅데이터 관련 수업을 들은 적이 있는데 뭔가 데이터 처리를 하기 전에 일단 데이터를 크롤링해와야 했던 과제가 있었다. 네이버 플레이스에서 맛집을 크롤링해보기로 해서 약 12만건? 정도 크��

liveyourit.tistory.com

 

 

JSON 데이터, 파이썬 객체로 변환

먼저, JSON 데이터를 파이썬 객체로 변환하기 위해 json 모듈loads()를 사용한다.

 

# start crawling
def crawling(self):
	
    # 코드...
    
    self.data = json.loads(data.text,encoding = 'utf-8')

 

 

파싱할 JSON 데이터 선정

JSON 데이터 중 어떤 키-값 을 파싱할지 정해야 한다. 크롤링하고 있는 JSON 데이터를 확인해보면, 음식점 정보가 items 내에 리스트 형태로 쭉 나열되어있다. 그리고 각 음식점마다 id, name, businessCategory 등 여러 값들이 저장되어 있는데 이 중에서 name, category, microReview, commonAddr, addr 데이터를 선정해서 파싱하도록 하겠다. 물론 당연하게도 본인이 원하는 값들을 정해서 파싱하면 된다.

 

 

 

JSON 데이터 파싱

이제 원하는 데이터를 파싱해서 저장하는 일만 남았다. 먼저, 각 음식점 정보가 items 내에 있었기 때문에 items에 먼저 접근해보겠다. items에 접근하려면 data["items"]를 해주면 된다.

 

# start crawling
def crawling(self):
	
    # 코드...
    
    self.data = json.loads(data.text,encoding = 'utf-8')
    print(self.data["items"])

 

 

파싱하기로 선정한 데이터에 접근하려면, data["items"][인덱스][키]를 해주면 된다. items 결과가 여러 개이기 때문에 꼭 인덱스를 지정해주어야 한다. 한 페이지 당 display를 100으로 설정해주었기 때문에 모든 값을 파싱하려면 인덱스 값을 0부터 증가시키는 과정이 필요하다.

 

# start crawling
def crawling(self):
	
    # 코드...
    
    self.data = json.loads(data.text,encoding = 'utf-8')
    print(self.data["items"][0]["name"])
    print(self.data["items"][0]["category"])
    print(self.data["items"][0]["desc"])
    print(self.data["items"][0]["microReview"])
    print(self.data["items"][0]["commonAddr"])
    print(self.data["items"][0]["addr"])

 

 

CRAWL 클래스 내의 crawling 함수에서는 display 길이만큼 반복문을 돌며 인덱스 값을 증가시키고, 실제 값을 파싱하는 코드는 get_json_value 함수에 작성하려 한다. 먼저 crawling 함수 코드를 보자. 참고로, 주석에 이전 코드들은 포스팅 상단에 링크해놓은 이전 포스팅에서 확인할 수 있고, 아니면 해당 포스팅 하단에 첨부해놓은 전체 코드를 확인하길 바란다.

 

diaplay 값만큼 반복문을 도는데 먼저 구와 동 정보를 self.write에 저장한다. self.write 변수는 리스트인데 구, 동, name, category, microReview, commonAddr, addr을 저장한 후 test.csv 파일에 저장해 줄 것이다. 구와 동 정보를 먼저 리스트에 추가한 후 self.get_json_value('키', '인덱스')를 호출하고 있다.

 

# start crawling
def crawling(self):

    print('[*] Start Crawling...')
    f = open('test.csv','w',encoding='utf-8-sig', newline='')
    f.close()
    
    # 코드...
    
	#parsing data from json 
	for i in range(display):

		self.write.append(gu)
		self.write.append(dong)
						
		self.get_json_value('name',i)
		self.get_json_value('category',i)
		self.get_json_value('microReview',i)
		self.get_json_value('commonAddr',i)
		self.get_json_value('addr',i)

 

 

self.get_json_value는 실제 json 값 파싱 기능을 하는 함수로 따로 작성해주었다. 넘어온 i 인덱스 값이 없을 수도 있기 때문에 (IndexError: list index out of range) try, except 구문을 사용했다. self.data["items"][i]에 key 가 들어있으면 value에 self.data["items"][i][key] 값을 저장한 후 self.write 리스트에 추가해준다. 

 

#parsing json data using items
def get_json_value(self,key,i):
		
	try:
		if key in self.data["items"][i]:
			value = self.data["items"][i][key]
			self.write.append(value)
		else:
			self.write.append("None")
	except:
		self.stop = 1

 

 

에러가 발생하면 self.stop 변수를 1로 설정해주는데, 이 변수가 1이 되면 반목문을 break하게 된다.

 

# start crawling
def crawling(self):

    print('[*] Start Crawling...')
    f = open('test.csv','w',encoding='utf-8-sig', newline='')
    f.close()
    
    # 코드...
    
	#parsing data from json 
	for i in range(display):
    
            # 코드...
            
            if self.stop == 1: break

 

 

크롤링 데이터 (JSON) csv 파일에 저장

이제 크롤링 및 파싱을 모두 완료했기 때문에 저장하는 일만 남았다. 앞서 crawling 함수 시작 지점에서 test.csv 파일을 생성해주었는데 csv에 한글을 저장 시, 깨지는 이슈가 있어 encoding='utf-8-sig' 옵션을 추가해주었다. 해당 파일을 열고, 파이썬 csv 모듈을 사용해 데이터(self.write)를 저장해준다. csv 파일을 열때는 개행이 두 번 들어가지 않도록, newline='' 옵션을 지정해준다.

 

# start crawling
def crawling(self):

    print('[*] Start Crawling...')
    f = open('test.csv','w',encoding='utf-8-sig', newline='')
    f.close()
    
    # 코드...
    
	#parsing data from json 
	for i in range(display):
    
            # 코드...
            
            with open ('test.csv','a',newline='') as f:
            	writer = csv.writer(f)
                writer.writerow(self.write)
                
            self.write = []

 

 

저장 결과는 아래와 같다.

 

 

 

크롤링 중간에 막히는 이슈 해결

크롤링을 하다 보니 어느샌가 크롤링이 막히는 이슈가 발생했다. 일정 데이터 이상 크롤링하고 나면, 존재하는 페이지인데도 내부 서버 500 에러가 발생해 더 이상 크롤링이 안 되는 것이다. 해당 이슈는 오늘 해결을 해보다가 해결이 되지 않아서 다음 포스팅 과제로 남겨놔야 할 것 같다고 했는데, 생각보다 빨리 해결이 됐다.

 

 

 

request를 하기 전에 sleep을 1이 아닌 5 정도로 주니, 중간에 막히는 문제가 완벽히 사라졌다.

 

# request url
time.sleep(5)
data = requests.get(url)

 

 

네이버 플레이스, 맛집 크롤링 전체 코드

전체 코드는 아래와 같다. 길다고 하면 긴 과정?을 마무리했는데, 약 10만 건 정도는 거뜬히 크롤링이 가능하니 크롤링한 데이터를 사용해 이다음에 다른 포스팅에서 이것저것 깨작깨작 해볼 예정이다.

 

#-*-coding:utf-8-*-
import os
import sys
import csv
import json
import time
import requests

class CRAWL:
	
	def __init__(self):
		
		self.seoul_dict = {}
		self.tmp_list = []
		self.data = []
		self.write = []
	
	# seoul_code.xlsx -> dictionary
	def get_seoul_code(self):
		
		dong_list = []
		with open("seoul_code.txt","rt",encoding='UTF8') as f:
			for line in f:
				if line == '\n':
					self.seoul_dict[key] = dong_list
					dong_list = []
					continue

				tmp = line.split(",")
				gu = tmp[0]
				dong = tmp[1].replace("\n","")

				dong_list.append(dong)
				key = gu		


	# parsing json data using items
	def get_json_value(self,key,i):
		
		try:
			if key in self.data["items"][i]:
				value = self.data["items"][i][key]
				self.write.append(value)
			else:
				self.write.append("None")
		except:
			self.stop = 1

	# start crawling
	def crawling(self):
		
		print('[*] Start Crawling...')
		f = open('test.csv','w',encoding='utf-8-sig', newline='')
		f.close()

		#loop for gu/dong
		for gu,dong_list in self.seoul_dict.items():
			print('-'+gu)

			for dong in dong_list:
				print('  -'+dong)

				gu_dong = gu+'+'+dong+'+'+u'맛집'
				display = 100
				
				self.stop = 0
                
				# send query
				for start in range(1,6):
					url = 'https://store.naver.com/sogum/api/businesses?start='+str(start) \
					+'&display='+str(display) \
					+'&query='+gu_dong \
					+'&sortingOrder=reviewCount' \

					time.sleep(5)
					#get data and check status code
					data = requests.get(url)
					if data.status_code == 500:
						break
					
					self.data = json.loads(data.text)
					
					#parsing data from json 
					for i in range(display):

						self.write.append(gu)
						self.write.append(dong)
						
						self.get_json_value('name',i)
						self.get_json_value('category',i)
						self.get_json_value('microReview',i)
						self.get_json_value('commonAddr',i)
						self.get_json_value('addr',i)
						
						if self.stop == 1:
							break

						with open ('test.csv','a',newline='') as f:
							writer = csv.writer(f)
							writer.writerow(self.write)

						self.write = []

			print('--------------------------------------')
            
if __name__ == "__main__":
	
	# gu = sys.argv[1]
	# dong = sys.argv[2]
	
	cr = CRAWL()
	cr.get_seoul_code()
	cr.crawling()

 


관련포스팅

[파이썬] 보안 뉴스 기사 크롤링하기 (제목, 본문 원하는만큼)

 

[파이썬] 보안 뉴스 기사 크롤링하기 (제목, 본문 원하는만큼)

뉴스 기사 크롤링 첫번째 - 보안뉴스 뉴스 기사 크롤링, 뉴스 기사 크롤러 만들기 첫번째 대상은 '보안뉴스' 이다. 왜냐면 내가 보안 종사자이기 때문이다. 어쨌든 보안뉴스 #전체기사 부분에서 �

liveyourit.tistory.com

[파이썬] 동적 웹 크롤링 (4) - Selenium을 이용한 비트코인 거래소 크롤링

 

[파이썬] 동적 웹 크롤링 (4) - Selenium을 이용한 비트코인 거래소 크롤링

이전 포스팅에서 알아보았던 Selenium(셀레니움) 사용법을 활용해서 비트코인 거래소 중 하나인 고팍스 메인페이지의 암호화폐 테이블 전체를 크롤링해서 엑셀에 저장해보려 한다. 참고로, webdrive

liveyourit.tistory.com

 

댓글

Designed by JB FACTORY