def update_or_create_from_melon(self, album_id): result = album_detail_crawler(album_id) album_title = result.get('album_title') # album_cover = result.get('album_cover') album_cover_url = result.get('album_cover_url') rel_date = result.get('rel_date') album, album_created = self.update_or_create( album_id=album_id, defaults={ 'title': album_title, # 'img_cover': album_cover, 'release_date': datetime.strptime(rel_date, '%Y.%m.%d'), }) temp_file = download(album_cover_url) file_name = '{album_id}.{ext}'.format( album_id=album_id, ext=get_buffer_ext(temp_file), ) # 방법1 - 지우고 다시 만들기 if album.img_cover: album.img_cover.delete() album.img_cover.save(file_name, File(temp_file)) return album, album_created
def update_or_create_from_melon(self, album_id): album_data = AlbumData(album_id) album_data.get_detail() album_id = album_data.album_id title = album_data.title url_img_cover = album_data.url_img_cover release_date_str = album_data.release_date album, album_created = self.update_or_create( melon_id=album_id, defaults={ 'title': title, 'release_date': datetime.strptime(release_date_str, '%Y.%m.%d') if release_date_str else None, }) temp_file = download(url_img_cover) file_name = '{album_id}.{ext}'.format( album_id=album_id, ext=get_buffer_ext(temp_file), ) # 중복데이터 제거 if album.img_cover: album.img_cover.delete() album.img_cover.save(file_name, File(temp_file)) return album, album_created
def add_from_search(self, request, url): search_result = CheckURL(url) search_result.check_url_from_parser() item_category = request.POST['category'] item_img = request.FILES.get('img', '') item_public_visibility = request.POST['public_visibility'] item_price = request.POST['price'].replace(',', '') item_name = request.POST['name'] if item_public_visibility == 'on' or item_public_visibility: item_public_visibility = True else: item_public_visibility = False item = self.create( user=request.user, name=item_name, purchase_url=search_result.item_data.url, price=item_price, category=item_category, img=item_img, public_visibility=item_public_visibility, ) if not item.img and search_result.item_data.item_img: item_img_url = search_result.item_data.item_img temp_file = download(item_img_url) file_name = '{urlparse}.{ext}'.format( urlparse=urlparse(item_img_url).path.split('/')[-1].split( '.')[0], ext=get_buffer_ext(temp_file)) item.img.save(file_name, File(temp_file)) return item
def update_or_create_from_melon(self, artist_id): from .artist import Artist artist = ArtistData(artist_id) artist.get_detail() name = artist.name url_img_cover = artist.url_img_cover real_name = artist.personal_information.get('본명', '') nationality = artist.personal_information.get('국적', '') birth_date_str = artist.personal_information.get('생일', '') constellation = artist.personal_information.get('별자리', '') blood_type = artist.personal_information.get('혈액형', '') # blood_type과 birth_date_str이 없을때 처리할것 # 튜플의 리스트를 순회하며 blood_type을 결정 for short, full in Artist.CHOICES_BLOOD_TYPE: if blood_type.strip() == full: blood_type = short break else: # break가 발생하지 않은 경우 # (미리 정의해놓은 혈액형 타입에 없을 경우) # 기타 혈액형값으로 설정 blood_type = Artist.BLOOD_TYPE_OTHER artist, artist_created = self.update_or_create( melon_id=artist_id, defaults={ 'name': name, 'real_name': real_name, 'nationality': nationality, 'birth_date': datetime.strptime(birth_date_str, '%Y.%m.%d') if birth_date_str else None, 'constellation': constellation, 'blood_type': blood_type, }) # img_profile필드에 저장할 파일확장자를 바이너리 데이터 자체의 MIME_TYPE에서 가져옴 # 파일명은 artist_id를 사용 temp_file = download(url_img_cover) file_name = '{artist_id}.{ext}'.format( artist_id=artist_id, ext=get_buffer_ext(temp_file), ) # artist.img_profile필드의 save를 따로 호출, 이름과 File객체를 전달 # (Django)File객체의 생성에는 (Python)File객체를 사용, # 이 때 (Python)File객체처럼 취급되는 BytesIO를 사용 if artist.img_profile: artist.img_profile.delete() artist.img_profile.save(file_name, File(temp_file)) return artist, artist_created
def authenticate(self, request, code): def get_access_token(auth_code): params_access_token = { 'client_id': self.CLIENT_ID, 'redirect_uri': 'http://localhost:8000/facebook-login/', 'client_secret': self.CLIENT_SECRET, 'code': auth_code, } response = requests.get(self.URL_ACCESS_TOKEN, params_access_token) response_dict = response.json() return response_dict['access_token'] def get_user_info(user_access_token): params = { 'access_token': user_access_token, 'fields': ','.join([ 'id', 'name', 'picture.width(2500)', 'first_name', 'last_name', ]) } response = requests.get(self.URL_ME, params) response_dict = response.json() return response_dict try: access_token = get_access_token(code) user_info = get_user_info(access_token) facebook_id = user_info['id'] name = user_info['name'] first_name = user_info['first_name'] last_name = user_info['last_name'] url_picture = user_info['picture']['data']['url'] try: user = User.objects.get(username=facebook_id) except User.DoseNotExist: user = User.objects.create_user( username=facebook_id, first_name=first_name, last_name=last_name, ) if not user.img_profile: temp_file = download(url_picture) ext = get_buffer_ext(temp_file) user.img_profile.save(f'{user.pk}.{ext}', File(temp_file)) return user except Exception: return None
def authenticate(self, request, access_token): params = { 'access_token': access_token, 'fields': ','.join([ 'id', 'name', 'picture.width(2500)', 'first_name', 'last_name', 'email', ]) } response = requests.get('https://graph.facebook.com/v2.12/me', params) if response.status_code == status.HTTP_200_OK: user_info = response.json() facebook_id = user_info['id'] name = user_info['name'] url_img_profile = user_info['picture']['data']['url'] # facebook유저중에 email이 없는 경우가 있어서 없는경우는 email을 빈값으로 입력 if 'email' in user_info: email = user_info['email'] else: email = '' try: # email이 unique이기 때문에 email로 구분한다. user = User.objects.get(username=facebook_id) except: user = User.objects.create_user( email=email, username=facebook_id, first_name=name, is_facebook_user=True, # img_profile=img_profile, # 이미지는 따로 저장한다. ) temp_file = download(url_img_profile) file_name = '{username}.{ext}'.format( username=facebook_id, ext=get_buffer_ext(temp_file), ) if user.img_profile: user.img_profile.delete() user.img_profile.save(file_name, File(temp_file)) return user
def update_or_create_from_melon(self, album_id): url = 'https://www.melon.com/album/detail.htm' params = { 'albumId': album_id, } response = requests.get(url, params) soup = BeautifulSoup(response.text, 'lxml') info = soup.select_one('div.section_info') entry = info.select_one('div.entry') src = info.select_one('div.thumb img').get('src') title = entry.select_one('div.info > .song_name').contents[2].strip() img_cover = re.search(r'(.*?)/melon/quality.*', src).group(1) # if re.findall('http.*?\.jpg', url_img_cover): # url_img_cover = re.findall('http.*?\.jpg', url_img_cover)[0] # else: # url_img_cover = "http://cdnimg.melon.co.kr/resource/image/web/default/noAlbum_500_160727.jpg" meta_dict = get_dict_from_dl(entry.select_one('div.meta dl')) # response = requests.get(url_img_cover) # binary_data = response.content # temp_file = BytesIO() # temp_file.write(binary_data) # # temp_file.seek(0) try: release_date = datetime.strptime(meta_dict['발매일'], '%Y.%m.%d') except ValueError: try: release_date = datetime.strptime(meta_dict['발매일'], '%Y.%m') except ValueError: try: release_date = datetime.strptime(meta_dict['발매일'], '%Y') except ValueError: release_date = None album, album_created = Album.objects.update_or_create( melon_id=album_id, defaults={ 'title': title, 'release_date': release_date, }) # file_name = Path(url_img_cover).name # file_name, temp_file = download(img_cover, album_id) temp_file = download(img_cover) file_name = '{album_id}.{ext}'.format( album_id=album_id, ext=get_buffer_ext(temp_file), ) album.img_cover.save(file_name, File(temp_file)) return album, album_created
def update_or_create_from_melon(self, artist_id): artist = ArtistData(artist_id) artist.get_detail() name = artist.name url_img_cover = artist.url_img_cover print(url_img_cover) real_name = artist.personal_information.get('본명', '') nationality = artist.personal_information.get('국적', '') birth_date_str = artist.personal_information.get('생일', '') constellation = artist.personal_information.get('별자리', '') blood_type = artist.personal_information.get('혈액형', '') for short, full in Artist.CHOICES_BLOOD_TYPE: if blood_type.strip() == full: blood_type = short break else: blood_type = Artist.BLOOD_TYPE_OTHER # if artist w/ melon_id = artist_id already exists, # update date in DB, # or add new artist in DB artist, artist_created = self.update_or_create( melon_id=artist_id, defaults={ 'name': name, 'real_name': real_name, 'nationality': nationality, 'birth_date': datetime.strptime(birth_date_str, '%Y.%m.%d') if birth_date_str else None, 'constellation': constellation, 'blood_type': blood_type, }) temp_file = download(url_img_cover) file_name = '{artist_id}.{ext}'.format( artist_id=artist_id, ext=get_buffer_ext(temp_file), ) if artist.img_profile: artist.img_profile.delete() artist.img_profile.save(file_name, File(temp_file)) return artist, artist_created
def update_or_create_from_melon(self, artist_id): from .artist import Artist artist = ArtistData(artist_id) artist.get_detail() name = artist.name url_img_cover = artist.url_img_cover real_name = artist.personal_information.get('본명', '') nationality = artist.personal_information.get('국적', '') birth_date_str = artist.personal_information.get('생일', '') constellation = artist.personal_information.get('별자리', '') blood_type = artist.personal_information.get('혈액형', '') # blood_type과 birth_date_str이 없을때 처리할것 # 튜플의 리스트를 순회하며 blood_type을 결정 for short, full in Artist.CHOICES_BLOOD_TYPE: if blood_type.strip() == full: blood_type = short break else: # break가 발생하지 않은 경우 # (미리 정의해놓은 혈액형 타입에 없을 경우) # 기타 혈액형값으로 설정 blood_type = Artist.BLOOD_TYPE_OTHER # artist_id가 melon_id에 해당하는 Artist가 이미 있다면 # 해당 Artist의 내용을 update # 없으면 Artist를 생성 artist, artist_created = self.update_or_create( melon_id=artist_id, defaults={ 'name': name, 'real_name': real_name, 'nationality': nationality, 'birth_date': datetime.strptime( birth_date_str, '%Y.%m.%d') if birth_date_str else None, 'constellation': constellation, 'blood_type': blood_type, } ) temp_file = download(url_img_cover) file_name = '{artist_id}.{ext}'.format( artist_id=artist_id, ext=get_buffer_ext(temp_file) ) if artist.img_profile: artist.img_profile.delete() artist.img_profile.save(file_name, File(temp_file)) return artist, artist_created
def update_or_create_from_melon(self, album_id): album_data = AlbumData(album_id) album_data.get_detail() album, album_created = self.update_or_create( melon_id=album_id, defaults={ 'title': album_data.title, 'release_date': album_data.release_date, }) temp_file = download(album_data.url_img_cover) file_name = '{album_id}.{ext}'.format( album_id=album_id, ext=get_buffer_ext(temp_file), ) album.img_cover.save(file_name, File(temp_file)) return album, album_created
def update_or_create_from_melon(self, album_id): # crawl url = 'https://www.melon.com/album/detail.htm' params = { 'albumId': album_id, } response = requests.get(url, params) soup = BeautifulSoup(response.text, 'lxml') url_img_cover_cont = soup.find('div', class_='thumb') info_cont = soup.find('div', class_='entry') # rsplit( separator, number of splits ) --> list url_img_cover = url_img_cover_cont.select_one( 'a.image_typeAll > img').get('src').rsplit('?', 1)[0] print(url_img_cover) title = info_cont.select_one( 'div.info > div.song_name strong').next_sibling.strip() release_date = info_cont.select_one( 'div.meta > dl.list > dd:nth-of-type(1)').text album, album_created = self.update_or_create(melon_id=album_id, defaults={ 'title': title, 'release_date': datetime.strptime( release_date, '%Y.%m.%d') }) temp_file = download(url_img_cover) file_name = '{album_id}.{ext}'.format( album_id=album_id, ext=get_buffer_ext(temp_file), ) # saving an img in a row creates new img file # why?? if album.img_cover: album.img_cover.delete() album.img_cover.save(file_name, File(temp_file)) return album, album_created
def save(self, *args, **kwargs): if Item.objects.filter(pk=self.pk): super().save() else: if self.purchase_url and not self.img: url = self.purchase_url search_result = CheckURL(url) search_result.check_url_from_parser() item_img_url = search_result.item_data.item_img if item_img_url: temp_file = download(item_img_url) file_name = '{urlparse}.{ext}'.format( urlparse=urlparse(item_img_url).path.split( '/')[-1].split('.')[0], ext=get_buffer_ext(temp_file)) self.purchase_url = search_result.item_data.url self.img.save(file_name, File(temp_file)) super().save()
def save(self, *args, **kwargs): # ImageField에 파일이 없고, url이 존재하는 경우에만 실행 if self.purchase_url and not self.image_file: # 우선 purchase_url의 대표 이미지를 크롤링하는 로직은 생략하고, 크롤링 결과 이미지 url을 임의대로 설정 item_image_url = 'https://cdn.pixabay.com/photo/2016/08/27/11/17/bag-1623898_960_720.jpg' if item_image_url: temp_file = download(item_image_url) file_name = '{urlparse}.{ext}'.format( # url의 마지막 '/' 내용 중 확장자 제거 # ex) url = 'https://~~~~~~/bag-1623898_960_720.jpg' # -> 'bag-1623898_960_720.jpg' # -> 'bag-1623898_960_720' urlparse=urlparse(item_image_url).path.split('/')[-1].split('.')[0], ext=get_buffer_ext(temp_file) ) self.image_file.save(file_name, File(temp_file)) super().save() else: super().save()
def authenticate(self, request, access_token): params = { 'access_token': access_token, 'fields': ','.join([ 'id', 'name', 'picture.width(2500)', 'first_name', 'last_name', 'email', ]) } response = requests.get('https://graph.facebook.com/v2.12/me', params) if response.status_code == status.HTTP_200_OK: # 응답상태 코드 200 이라면 response_dict = response.json() facebook_id = response_dict['id'] name = response_dict['name'] if name == '': first_name = response_dict['first_name'] last_name = response_dict['last_name'] name = last_name + first_name url_picture = response_dict['picture']['data']['url'] user, _ = User.objects.get_or_create(username=facebook_id, email=None, nickname=name) if not user.img_profile: temp_file = download(url_picture) ext = get_buffer_ext(temp_file) im = Image.open(temp_file) large = im.resize((200, 200)) temp_file = BytesIO() large.save(temp_file, ext) user.img_profile.save(f'{user.pk}.{ext}', File(temp_file)) return user
def update_or_create_from_melon(self, album_id): album_data = AlbumData(album_id) album_data.get_detail() album, album_created = self.update_or_create( melon_id=album_id, defaults={ 'title': album_data.title, 'release_date': album_data.release_date, } ) # response = requests.get(album_data.url_img_cover) # binary_data = response.content # temp_file = BytesIO() # temp_file.write(binary_data) # temp_file.seek(0) # file_name = Path(album_data.url_img_cover).name temp_file = download(album_data.url_img_cover) file_name = '{album_id}.{ext}'.format( album_id=album_id, ext=get_buffer_ext(temp_file), ) album.img_cover.save(file_name, File(temp_file)) return album, album_created
def update_or_create_from_melon(self, artist_id): artist = ArtistData(artist_id) artist.get_detail() name = artist.name url_img_cover = artist.url_img_cover real_name = artist.personal_information.get('본명', '') nationality = artist.personal_information.get('국적', '') birth_date_str = artist.personal_information.get('생일', '') constellation = artist.personal_information.get('별자리', '') blood_type = artist.personal_information.get('혈액형', '') # blood_type과 birth_date_str이 없을때 처리할것 # 튜플의 리스트를 순회하며 blood_type을 결정 for short, full in Artist.CHOICES_BLOOD_TYPE: if blood_type.strip() == full: blood_type = short break else: # break가 발생하지 않은 경우 # (미리 정의해놓은 혈액형 타입에 없을 경우) # 기타 혈액형값으로 설정 blood_type = Artist.BLOOD_TYPE_OTHER # url_img_cover는 이미지의 URL response = requests.get(url_img_cover) # requests에 GET요청을 보낸 결과의 Binary data binary_data = response.content # 파일처럼 취급되는 메모리 객체 temp_file를 생성 temp_file = BytesIO() # temp_file에 이진데이터를 기록 temp_file.write(binary_data) # 파일객체의 포인터를 시작부분으로 되돌림 # temp_file.seek(0) # 해보니 위 seek 이 없어도 저장됨.. # url 뒤에 붙어서 확장자 이상하게 저장되는 것만 막으면 됨 artist, artist_created = self.update_or_create( melon_id=artist_id, defaults={ 'name': name, 'real_name': real_name, 'nationality': nationality, 'birth_date': datetime.strptime(birth_date_str, '%Y.%m.%d') if birth_date_str else None, 'constellation': constellation, 'blood_type': blood_type, }) temp_file = download(url_img_cover) file_name = '{artist_id}.{ext}'.format( artist_id=artist_id, ext=get_buffer_ext(temp_file), ) # artist.img_profile필드의 save를 따로 호출, 이름과 File객체를 전달 # (Django)File객체의 생성에는 (Python)File객체를 사용, # 이 때 (Python)File객체처럼 취급되는 BytesIO를 사용 artist.img_profile.save(file_name, File(temp_file)) return artist, artist_created
def update_or_create_from_song_id(self, song_id): """ Song의 Album정보도 가져와서 AlbumManager.update_or_create_from_melon도 실행 -> Album의 커버이미지도 저장 """ url_song = 'https://www.melon.com/song/detail.htm' params_song = { 'songId': song_id, } response_song = requests.get(url_song, params_song) soup_song = BeautifulSoup(response_song.text, 'lxml') thumb_entry = soup_song.find('div', class_='thumb') url_img_cover = thumb_entry.find('img').get('src') # if re.findall('http.*?\.jpg', url_img_cover): # url_img_cover = re.findall('http.*?\.jpg', url_img_cover)[0] # else: # url_img_cover = "http://cdnimg.melon.co.kr/resource/image/web/default/noAlbum_500_160727.jpg" div_entry = soup_song.find('div', class_='entry') title = div_entry.find('div', class_='song_name').strong.next_sibling.strip() artist = div_entry.find('div', class_='artist').get_text(strip=True) if div_entry.select_one('div.artist a'): artist_id_a = div_entry.select_one('div.artist a').get('href') artist_id = re.findall(r'\(\'(.*?)\'\)', artist_id_a)[0] else: artist_id = '100014' # 앨범, 발매일, 장르...에 대한 Description list dl = div_entry.find('div', class_='meta').find('dl') # isinstance(인스턴스, 클래스(타입)) # items = ['앨범', '앨범명', '발매일', '발매일값', '장르', '장르값'] items = [item.get_text(strip=True) for item in dl.contents if not isinstance(item, str)] it = iter(items) description_dict = dict(zip(it, it)) album = description_dict.get('앨범') album_id_a = str(dl.select_one('a')) album_id = re.findall(r'\(\'(.*?)\'\)', album_id_a)[0] # release_date = description_dict.get('발매일') genre = description_dict.get('장르') div_lyrics = soup_song.find('div', id='d_video_summary') lyrics_list = [] if div_lyrics: for item in div_lyrics: if item.name == 'br': lyrics_list.append('\n') elif type(item) is NavigableString: lyrics_list.append(item.strip()) lyrics = ''.join(lyrics_list) else: lyrics = '가사가 없습니다' # # if Album.objects.get(title=album): # # url_img_cover는 이미지의 URL # response = requests.get(url_img_cover) # # requests에 GET요청을 보낸 결과의 Binary data # binary_data = response.content # # 파일처럼 취급되는 메모리 객체 temp_file를 생성 # temp_file = BytesIO() # # temp_file에 이진데이터를 기록 # temp_file.write(binary_data) # # 파일객체의 포인터를 시작부분으로 되돌림 # # temp_file.seek(0) # artist = ArtistData(artist_id) # artist.get_detail() # # name = artist.name # url_img_cover = artist.url_img_cover # url_img_cover = re.findall('http.*?\.jpg', url_img_cover)[0] # real_name = artist.personal_information.get('본명', '') # nationality = artist.personal_information.get('국적', '') # birth_date_str = artist.personal_information.get('생일', '') # if not birth_date_str or len(birth_date_str) <= 9: # birth_date_str = '1900.01.01' # constellation = artist.personal_information.get('별자리', '') # blood_type = artist.personal_information.get('혈액형', '') # # for short, full in Artist.CHOICES_BLOOD_TYPE: # if blood_type.strip() == full: # blood_type = short # break # else: # blood_type = Artist.BLOOD_TYPE_OTHER # # response = requests.get(url_img_cover) # binary_data = response.content # temp_file = BytesIO() # temp_file.write(binary_data) # temp_file.seek(0) # # artist, _ = Artist.objects.update_or_create( # melon_id=artist_id, # defaults={ # 'name': name, # 'real_name': real_name, # 'nationality': nationality, # 'birth_date': datetime.strptime(birth_date_str, '%Y.%m.%d'), # 'constellation': constellation, # 'blood_type': blood_type, # } # ) # # file_name = Path(url_img_cover).name # artist.img_profile.save(file_name, File(temp_file)) # album, _ = Album.objects.update_or_create_from_melon(album_id) # song.album.add(album) song, song_created = Song.objects.update_or_create( song_id=song_id, defaults={ # 'album': Album.objects.get(title=album), 'title': title, 'genre': genre, 'lyrics': lyrics, 'album': album, } ) artist, _ = Artist.objects.update_or_create_from_melon(artist_id) song.artists.add(artist) # file_name = Path(url_img_cover).name # file_name, temp_file = download(url_img_cover, song_id) temp_file = download(url_img_cover) file_name = '{song_id}.{ext}'.format( song_id=song_id, ext=get_buffer_ext(temp_file), ) song.img_cover.save(file_name, File(temp_file)) return song, song_created
def authenticate(self, request, code): def get_access_token(auth_code): """ 유저가 페이스북에서 우리 애플리케이션의 사용에 대해 '승인'한 경우, 페이스북에서 우리 애플리케이션의 주소(redirect_uri)에 'code'라는 GET parameter로 전해주는 인증 코드 (auth_code)를 사용해서 페이스북 GraphAPI에 access_token요청, 결과를 가져와 리턴 :param auth_code: 유저가 페이스북에 로그인/앱 승인한 결과로 돌아오는 'code' GET parameter :return: """ redirect_uri = 'http://localhost:8000/facebook-login/' # 아래 엔드포인트에 GET요청을 보냄 params_access_token = { 'client_id': self.CLIENT_ID, 'redirect_uri': redirect_uri, 'client_secret': self.CLIENT_SECRET, 'code': auth_code, } response = requests.get(self.URL_ACCESS_TOKEN, params_access_token) # 전송받은 결과는 JSON형식의 텍스트. requests가 제공하는 JSON 디코더를 사용해서 # JSON텍스트를 Python dict로 변환해준다 response_dict = response.json() return response_dict['access_token'] def get_user_info(user_access_token): """ User access token을 사용해서 GraphAPI의 'User'항목을 리턴 (엔드포인트 'me'를 사용해서 access_token에 해당하는 사용자의 정보를 가져옴) :param user_access_token: 정보를 가져올 Facebook User access token :return: User정보 (dict) """ params = { 'access_token': user_access_token, 'fields': ','.join([ 'id', 'name', 'picture.width(2500)', 'first_name', 'last_name', ]) } response = requests.get(self.URL_ME, params) response_dict = response.json() return response_dict # try: access_token = get_access_token(code) user_info = get_user_info(access_token) facebook_id = user_info['id'] name = user_info['name'] first_name = user_info['first_name'] last_name = user_info['last_name'] url_picture = user_info['picture']['data']['url'] try: user = User.objects.get(username=facebook_id) except User.DoesNotExist: user = User.objects.create_user( username=facebook_id, first_name=first_name, last_name=last_name, ) if not user.img_profile: temp_file = download(url_picture) ext = get_buffer_ext(temp_file) user.img_profile.save(f'{user.pk}.{ext}', File(temp_file)) return user
def authenticate(self, request, code): def get_access_token(auth_code): """ 유저가 페이스북에서 우리 애플리케이션의 사용에 대해 '승인'한 경우, 페이스북에서 우리 애플리케이션의 주소(redirect_uri)에 'code'라는 GET parameter로 전해주는 인증 코드 (auth_code)를 사용해서 페이스북 GraphAPI에 access_token요청, 결과를 가져와 리턴 :param auth_code: 유저가 페이스북에 로그인/앱 승인한 결과로 돌아오는 'code' GET parameter :return: """ redirect_uri = 'http://localhost:8000/facebook-login/' # 아래 엔드포인트에 GET요청을 보냄 params_access_token = { 'client_id': self.CLIENT_ID, 'redirect_uri': redirect_uri, 'client_secret': self.CLIENT_SECRET, 'code': auth_code, } response = requests.get(self.URL_ACCESS_TOKEN, params_access_token) # 전송받은 결과는 JSON형식의 텍스트. requests가 제공하는 JSON 디코더를 사용해서 # JSON텍스트를 Python dict로 변환해준다 response_dict = response.json() return response_dict['access_token'] def get_user_info(user_access_token): """ User access token을 사용해서 GraphAPI의 'User'항목을 리턴 (엔드포인트 'me'를 사용해서 access_token에 해당하는 사용자의 정보를 가져옴) :param user_access_token: 정보를 가져올 Facebook User access token :return: User정보 (dict) """ params = { 'access_token': user_access_token, 'fields': ','.join([ 'id', 'name', 'picture.width(2500)', 'first_name', 'last_name', ]) } response = requests.get(self.URL_ME, params) response_dict = response.json() return response_dict try: # -> 아래 인증과정에서 오류가 발생할 경우 # None을 리턴할 수 있도록. access_token = get_access_token(code) user_info = get_user_info(access_token) facebook_id = user_info['id'] name = user_info['name'] first_name = user_info['first_name'] last_name = user_info['last_name'] url_picture = user_info['picture']['data']['url'] try: # -> 회원가입되지 않은 유저의 경우 예외처리 user = User.objects.get(username=facebook_id) except User.DoesNotExist: user = User.objects.create_user( username=facebook_id, first_name=first_name, last_name=last_name, # img_profile=, ) # file_name = '{album_id}.{ext}'.format( # album_id=album_id, # ext=get_buffer_ext(temp_file), # ) # 방법1 - 지우고 다시 만들기 # if album.img_cover: # album.img_cover.delete() # 사진이 없을 때만 저장하는 것으로 간단하게 실습. if not user.img_profile: temp_file = download(url_picture) ext = get_buffer_ext(temp_file) user.img_profile.save( f'{user.pk}-{user.first_name}{user.last_name}.{ext}', File(temp_file)) return user # binary_data = request.get(url_picture) # user.img_profile.save(facebook_id, ContentFile(binary_data)) except Exception: return None
def update_or_create_from_melon(self, artist_id): from artist.models import Artist ###################### add_from_melon.py ###################### ################# 크롤러 ################# import requests from bs4 import BeautifulSoup url = f'https://www.melon.com/artist/detail.htm' params = { 'artistId': artist_id, } response = requests.get(url, params) source = response.text soup = BeautifulSoup(source, 'lxml') # name name = soup.select_one('p.title_atist').strong.next_sibling # url_img_cover url_img = soup.select_one('span#artistImgArea > img').get('src') url_img_cover = re.search(r'(.*.jpg)', url_img).group(1) # real_name, nationality, birth_date, constellation, blood_type personal_information = {} if re.search(r'신상정보</h3>', source, re.DOTALL): dl_list = re.search(r'신상정보</h3>.*?-->(.*?)</dl>', source, re.DOTALL) # dt = re.findall('<dt>.*?</dt>', dl_list.group(1)) # dd = re.findall('<dd>.*?</dd>', dl_list.group(1)) soup = BeautifulSoup(dl_list.group(), 'lxml') dt = soup.select('dt') dd = soup.select('dd') dd_dt = list(zip(dt, dd)) # print(dd_dt) for i, j in dd_dt: i = i.get_text(strip=True) j = j.get_text(strip=True) personal_information[i] = j # print(self._personal_information) else: personal_information = '' ####################################### # url_img_cover = artist.url_img_cover real_name = personal_information.get('본명', '') nationality = personal_information.get('국적', '') birth_date_str = personal_information.get('생일', '') constellation = personal_information.get('별자리', '') blood_type = personal_information.get('혈액형', '') # 예외처리 1 # 튜플의 리스트를 순회하며 blood_type을 결정 for short, full in Artist.CHOICES_BLOOD_TYPE: if blood_type.strip() == full: blood_type = short break else: # break가 발생하지 않은 경우 # (미리 정의해놓은 혈액형 타입에 없을 경우) # 기타 혈액형값으로 설정 blood_type = Artist.BLOOD_TYPE_OTHER # 예외처리 2 - 생년월일 없을 경우 # if birth_date_str == '': # birth_date = None # else: # birth_date = datetime.strptime(birth_date_str, '%Y.%m.%d') # 예외처리 2-2 - 위의 4줄을 한 줄로 줄임 # datetime.strptime(birth_date_str, '%Y.%m.%d') if birth_date_str else None, # 1단계 - Artist 생성 # Artist.objects.create( # melon_id=artist_id, # name=name, # real_name=real_name, # nationality=nationality, # birth_date=datetime.strptime(birth_date_str, '%Y.%m.%d'), # constellation=constellation, # blood_type=blood_type, # ) # artist_id가 melon_id에 해당하는 Artist가 이미 있다면 # 해당 Artist의 내용을 update, # 없으면 Artist를 생성 # 2단계 - 코드가 두번 반복됨, 암걸릴 것 같음. # if Artist.objects.filter(melon_id=artist_id).exists(): # artist = Artist.objects.get(melon_id=artist_id) # artist.melon_id = artist_id # artist.name = name # artist.real_name = real_name # artist.nationality = nationality # artist.birth_date = datetime.strptime(birth_date_str, '%Y.%m.%d') # artist.constellation = constellation # artist.blood_type = blood_type # artist.save() # else: # Artist.objects.create( # melon_id=artist_id, # name=name, # real_name=real_name, # nationality=nationality, # birth_date=datetime.strptime(birth_date_str, '%Y.%m.%d'), # constellation=constellation, # blood_type=blood_type, # ) # 3단계 - get_or_create() 사용 # artist, artist_created = Artist.objects.get_or_create(melon_id=artist_id) # artist.name = name # artist.real_name = real_name # artist.nationality = nationality # artist.birth_date = datetime.strptime(birth_date_str, '%Y.%m.%d') # artist.constellation = constellation # artist.blood_type = blood_type # artist.save() # return redirect('artist:artist-list') # -> 문제점: save()가 두번 발생함. 이미 존재하면 가져오고 # 속성을 변경하고 save()를 하면 되는데, created할 때는 # 객체를 만들 때 save()를 한번 하고 밑에서 또 한번 save()를 함. ######## Save file to ImageField ######## from io import BytesIO from pathlib import Path from django.core.files import File from django.core.files.base import ContentFile # response = requests.get(url_img_cover) # binary_data = response.content # img_profile필드에 저장할 파일명을 전체 URL경로에서 추출 (Path라이브러리) # file_name = Path(url_img_cover).name # print(f'file_name: {file_name}') # 방법1 - 2/20 수업시간 # 파일처럼 취급되는 메모리 객체 temp_file를 생성 # temp_file = BytesIO() # temp_file에 이진데이터를 기록 # temp_file.write(binary_data) # 파일객체의 포인터를 시작부분으로 되돌림 # temp_file.seek(0) # artist.img_profile필드의 save를 따로 호출, 이름과 File객체를 전달 # (Django)File객체의 생성에는 (Python)File객체를 사용, # 이때 (Python)File객체처럼 취급되는 BytesIO를 사용 # artist.img_profile.save(file_name, File(temp_file)) # -> update_or_create에서 반환된 obj인 'artist'를 활용하기 때문에 # 이 방법1 을 실행하려면 아래쪽으로 이동시킬 것. # 방법2 - ContentFile이용 by che1 # # artist.img_profile.save(file_name, ContentFile(binary_data)) # -> update_or_create에서 반환된 obj인 'artist'를 활용하기 때문에 # 이 방법2 를 실행하려면 아래쪽으로 이동시킬 것. # 방법 3 - update_or_create 이용해서 이미지 저장하기 # # 아래에서 # 'img_profile': ContentFile(binary_data, name='test.jpg'), # 이 부분이 방법 3 # 방법 4 - 위 방법으로 사진 중복저장을 막지 못해서 이 방법 4 생각해냄. # if (파일이 안같으면): # 기존 사진 지우는 코드 (기존 사진에서 업데이트 되었으므로) # img = ContentFile(binary_data, filename) # else: (파일이 같으면) # pass # 4단계 -update_or_create() 사용 # 1) # artist, artist_created = Artist.objects.update_or_create( # 2) self.model이라는 이름으로 자신의 클래스에 접근가능 # artist, artist_created = self.model.update_or_create( # 3) objects라는 것 자체가 매니저 객체였으니까 매니저 객체에 있는 # 이 update_or_create를 그대로 실행하면 되는 거죠. # (밖으로 나갔다가 다시 들어올 필요없이) artist, artist_created = self.update_or_create( melon_id=artist_id, defaults={ 'name': name, 'real_name': real_name, 'nationality': nationality, # 'birth_date': birth_date, # 위의 예외처리 4줄 대신 '조건표현식' 한줄로 Pythonic하게! 'birth_date': datetime.strptime(birth_date_str, '%Y.%m.%d') if birth_date_str else None, 'constellation': constellation, 'blood_type': blood_type, # 방법 3 # 'img_profile': ContentFile(binary_data, name='test.jpg'), # 이런식으로 name에다가 값을 전달해주면 해당 값이 파일명이 됨. # 'img_profile': ContentFile(binary_data, name=file_name), # 방법 4 # 'img_profile': img #-> 방법 4 쓴다면 } ) # 2/23 # import magic # # mime_type = magic.from_buffer(temp_file.read(), mime=True) # file_name = '{artist_id}.{ext}'.format( # artist_id=artist_id, # ext=mime_type.split('/')[-1] # ) # 위 코드를 utils/file.py로 분리함 # 전달인자로 url과 artist_id를 전달함 (원래 두번째 인자는 artist_id는 아님) # file_name, temp_file = download(url_img_cover, artist_id) # img_profile필드에 저장할 파일확장자를 바이너리 데이터 자체의 MIME_TYPE에서 가져옴 # 파일명은 artist_id를 사용 temp_file = download(url_img_cover) file_name = '{artist_id}.{ext}'.format( artist_id=artist_id, ext=get_buffer_ext(temp_file), ) # 2/23 - 사진 중복저장 방지 코드 # : 해당필드에 사진이 있는지 확인 # 방법1 - 지우고 다시 만들기 if artist.img_profile: artist.img_profile.delete() artist.img_profile.save(file_name, File(temp_file)) # 방법2 - 있을경우 안만들기 # if not artist.img_profile: # artist.img_profile.save(file_name, File(temp_file)) return artist, artist_created
city, _ = CityInformation.objects.get_or_create( name=travel_info['city'], continent='Europe', nationality=travel_info['country'], ) # 도시이미지 저장부분 url_img_city = requests.get(travel_info['city_img_url']) binary_data = url_img_city.content temp_file = BytesIO() temp_file.write(binary_data) temp_file.seek(0) file_name = '{city_id}.{img}.{ext}'.format( city_id=id, img=datetime.now(), ext=get_buffer_ext(temp_file), ) city.city_image.save(file_name, File(temp_file)) # 가이드 정보 저장 company, _ = CompanyInformation.objects.get_or_create( name=travel_info['guide_name'], info=travel_info['guide_description'], ) # 가이드 이미지 저장 url_img_company = requests.get(travel_info['city_img_url']) binary_data = url_img_company.content temp_file = BytesIO() temp_file.write(binary_data) temp_file.seek(0) file_name = '{company_id}.{img}.{ext}'.format(
def authenticate(self, request, code): def get_access_token(auth_code): """ user가 facebook에서 melon 어플리케이션의 사용에 대해 '승인'한 경우 facebook에서 melon 어플리케이션의 주소(redirect_uri)에 'code'라는 GET parameter로 전해주는 인증코드(auth_code)를 사용해서 페이스북 GraphAPI에 access_token요청, 결과를 가져와 리 :param auth_code: 유저가 페이스북에 로그인/앱 승인한 결과로 돌아오는 'code' GET parameter :return: """ redirect_uri = "http://localhost:8000/facebook-login/" params_access_token = { 'client_id': self.CLIENT_ID, 'redirect_uri': redirect_uri, 'client_secret': self.CLIENT_SECRET, 'code': auth_code, } response = requests.get(self.URL_ACCESS_TOKEN, params_access_token) response_dict = response.json() return response_dict['access_token'] def get_user_info(user_access_token): """ User access token을 사용해서 GraphAPI의 'User'항목을 리턴 (엔드포인트 'me'를 사용해서 access_token에 해당하는 사용자의 정보를 가져옴) :param user_access_token: 정보를 가져올 facebook user access token :return: User 정보(dict) """ params = { 'access_token': user_access_token, 'fields': ','.join([ 'id', 'name', 'picture.width(2500)', 'first_name', 'last_name', ]) } response = requests.get(self.URL_ME, params) response_dict = response.json() return response_dict # {'id': '1746683798704556', 'name': 'S eokJae Hong', 'picture': {'data': {'height': 1079, 'is_silhouette': False, 'url': 'https://scontent.xx.fbcdn.net/v/t31.0-1/16904750_1386387041400902_7254244577969287703_o.jpg?oh=4bfe02828716d67e65fa5b422f32c6a3&oe=5B0B6A0E', 'width': 1092}}, 'first_name': 'SeokJae', 'last_name': 'Hong'} try: access_token = get_access_token(code) user_info = get_user_info(access_token) facebook_id = user_info['id'] name = user_info['name'] first_name = user_info['first_name'] last_name = user_info['last_name'] url_picture = user_info['picture']['data']['url'] try: user = User.objects.get(username=facebook_id) except: user = User.objects.create_user( username=facebook_id, first_name=first_name, last_name=last_name, ) temp_file = download(url_picture) file_name = '{username}.{ext}'.format( username=facebook_id, ext=get_buffer_ext(temp_file), ) if user.img_profile: user.img_profile.delete() user.img_profile.save(file_name, File(temp_file)) return user except Exception: return None
def update_or_create_from_melon(self, artist_id): artist = ArtistData(artist_id) artist.get_detail() name = artist.name url_img_cover = artist.url_img_cover # .get: dict에서 key있으면 반환 없으면 '' real_name = artist.personal_information.get('본명', '') nationality = artist.personal_information.get('국적', '') birth_date_str = artist.personal_information.get('생일', '') constellation = artist.personal_information.get('별자리', '') blood_type = artist.personal_information.get('혈액형', '') for short, full in Artist.CHOICE_BLOOD_TYPE: if blood_type.strip() == full: blood_type = short break else: blood_type = Artist.BLOOD_TYPE_OTHER artist, artist_created = self.update_or_create( melon_id=artist_id, defaults={ 'name': name, 'real_name': real_name, 'nationality': nationality, 'birth_date': datetime.strptime(birth_date_str, '%Y.%m.%d') if birth_date_str else None, 'constellation': constellation, 'blood_type': blood_type, }) # img_profile필드에 저장할 파일확장자를 바이너리 데이터 자체의 MIME_TYPE에서 가져옴 # 파일명은 artist_id를 사용 # # def download(url): # # url로부터 다운받은 데이터를 BytesIO객체에 쓰고 리턴 # response = requests.get(url) # binary_data = response.content # temp_file = BytesIO() # temp_file.write(binary_data) # temp_file.seek(0) # return temp_file # def get_buffer_ext(buffer): # buffer.seek(0) # mime_info = magic.from_buffer(buffer.read(), mime=True) # buffer.seek(0) # return mime_info.split('/')[-1] temp_file = download(url_img_cover) file_name = '{artist_id}.{ext}'.format( artist_id=artist_id, ext=get_buffer_ext(temp_file), ) if artist.img_profile: artist.img_profile.delete() artist.img_profile.save(file_name, File(temp_file)) return artist, artist_created