파이썬으로 셀러리움 웹페이지 창 뛰우기
options.add_argument('headless')
이 옵션으로 창이 보이지 않게 된다.
options.add_argument("lang=ko_KR")
이 옵션으로 언어를 설정할수가 있다.
기본언어를 다른언어로 설정하고싶을때 수정해서 사용하면 유용하다.
options.add_argument('--start-maximized')
이 옵션으로 창을 최대화 해서 뛰울수가 있다.
동적 웹페이지에서 보다 많은 데이터를 읽을수 있는 장점이 있다.
chrome_ver = chromedriver_autoinstaller.get_chrome_version().split('.')[0]
try:
browser = webdriver.Chrome(f'./{chrome_ver}/chromedriver.exe',options=options)
except:
chromedriver_autoinstaller.install(True)
browser = webdriver.Chrome(f'./{chrome_ver}/chromedriver.exe',options=options)
browser.implicitly_wait(10)
크롬드라이버가 자주 업데이트 되는데 그때마다 크롬드라이버를 새로 까는 것이 매우 귀찮을것이다. 이 코드로 깔끔하게 해결된다. 자동으로 크롬드라이버를 깔아서 실행해준다.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import chromedriver_autoinstaller
options = Options()
#headless모드 브라우저가 뜨지 않고 실행됩니다.
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" #크롬
options.add_argument('user-agent=' + user_agent)
options.add_argument('headless')
options.add_argument("no-sandbox")
options.add_argument("lang=ko_KR")
#창 최대화
options.add_argument('--start-maximized') #브라우저가 최대화된 상태로 실행됩니다.
options.add_argument("disable-gpu") ## 그래픽카드 기능을 제거함으로써 셀레니움 작동 속도를 높여줍니다.
chrome_ver = chromedriver_autoinstaller.get_chrome_version().split('.')[0]
try:
browser = webdriver.Chrome(f'./{chrome_ver}/chromedriver.exe',options=options)
except:
chromedriver_autoinstaller.install(True)
browser = webdriver.Chrome(f'./{chrome_ver}/chromedriver.exe',options=options)
browser.implicitly_wait(10)
browser.get(url)
셀레니움 wait 두가지 개념익히기
from selenium import webdriver
driver = webdriver.Chrome('chromedriver.exe')
driver.implicitly_wait(10)
implicitly_wait 는 쉽게 설명하자면 페이지 이동등의 명령어를 줬을 때 다음 웹페이지가 넘어올때까지 기다리라는 뜻이다. 드라이버를 열고 나서 한번만 설정해주면 된다. 위 예제에서 괄호 안에 숫자의 의미는 10초동안 웹페이지가 로딩될때까지 기다리고 10초가 넘어가면 웹페이지가 로딩이 됐던 안됐던 다음 명령어를 실행하겠다는 것이다. 자신의 컴퓨터가 너무 느리다면 60초 즉 1분을 설정해도 상관없다.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome('chromedriver.exe')
driver.get("https://pythondocs.net")
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "idname")))
element = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'someid')))
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "idname")))
WebDriverWait(driver, 10) 10초까지 해당 element 가 나올때 까지 기다려보겠다는 의미이다. 10초 전에 나오면 해당 element 값이 변수로 저장될것이다.
element = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'someid')))
이것도 위와 비슷하다. 해당 요소가 클릭할수 있을때 까지 10초간 기다린다.
위 두가지를 병행해서 사용해도 부족할때가 있을것이다. 그럴땐 적절히 time.sleep 를 사용해야 할것이다.
마우스 스크롤 하기
동적 페이지일경우 마우스를 스크롤하면 데이터가 더 나오는 경우가 많다. 이럴때 마우스를 스크롤하는 코드이다.
prev_height = browser.execute_script("return document.body.scrollHeight")
while TRUE:
browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")
time.sleep(2)
curr_height = browser.execute_script("return document.body.scrollHeight")
if curr_height == prev_height:
break
print(prev_height)
print(curr_height)
prev_height=curr_height
time.sleep(2)
print("스크롤 완료")
위 방법으로 마우스 스크롤이 안될때가 있다. 아이프레임 안에 스크롤 막대가 있다던지 아니면 새로운 창이 하나 뜬 상태일때 사용하면 좋다.
def scroll(modal):
try:
# 스크롤 높이 받아오기
last_height = driver.execute_script("return arguments[0].scrollHeight", modal)
while True:
pause_time = random.uniform(0.5, 0.8)
# 최하단까지 스크롤
driver.execute_script("arguments[0].scrollTo(0, arguments[0].scrollHeight);", modal)
# 페이지 로딩 대기
time.sleep(pause_time)
# 무한 스크롤 동작을 위해 살짝 위로 스크롤
driver.execute_script("arguments[0].scrollTo(0, arguments[0].scrollHeight-50);", modal)
time.sleep(pause_time)
# 스크롤 높이 새롭게 받아오기
new_height = driver.execute_script("return arguments[0].scrollHeight", modal)
try:
# '더보기' 버튼 있을 경우 클릭
all_review_button = driver.find_element_by_xpath('/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div/main/div/div[1]/div[2]/div[2]/div/span/span').click()
except:
# 스크롤 완료 경우
if new_height == last_height:
print("스크롤 완료")
break
last_height = new_height
except Exception as e:
print("에러 발생: ", e)
modal = WebDriverWait(driver, 2).until(EC.element_to_be_clickable((By.XPATH, "")))
scroll(modal)
특정 요소 찾기 클릭하기 내용입력하기 텍스트 가져오기
특정요소를 찾는 방법은 아래를 참고하자.
from selenium.webdriver.common.by import By
driver.find_element(By.XPATH, '//button[text()="Some text"]')
driver.find_element(By.XPATH, '//button')
driver.find_element(By.ID, 'loginForm')
driver.find_element(By.LINK_TEXT, 'Continue')
driver.find_element(By.PARTIAL_LINK_TEXT, 'Conti')
driver.find_element(By.NAME, 'username')
driver.find_element(By.TAG_NAME, 'h1')
driver.find_element(By.CLASS_NAME, 'content')
driver.find_element(By.CSS_SELECTOR, 'p.content')
특정요소 클릭하는 코드는 아래를 참고하자.
driver.find_element_by_xpath("//form[@class='ui form']/button").click()
위 방법으로 클릭이 되지 않는다면 아래 방법을 시도해보면 된다.
from selenium.webdriver.common.keys import Keys
driver.find_element_by_xpath("//form[@class='ui form']/button").send_keys(Keys.ENTER)
인풋박스에 내용입력하는 방법은 아래를 참고하자. 네이버 아이디와 비번을 입력하고 로그인 버튼을 누르는 예시다.
from selenium.webdriver.common.keys import Keys
browser.find_element_by_id('id').send_keys('naver_id')
browser.find_element_by_id('pw').send_keys('naver_password')
browser.find_element_by_id('log.login').click()
find_element 를 이용해서 간다히 텍스트를 추출할수도 있다. 간단히 특정한 한개의 텍스트만 추출할때 사용하면 유용하다.
textdata=driver.find_element(By.XPATH, '//button[text()="Some text"]').text
print(textdata)
크롤링된 데이터 가공하기
find 를 사용해서 데이터를 추출하는 예제1
browser.get(call_url1)
soup=BeautifulSoup(browser.page_source,"lxml")
datas=soup.find("div",attrs={"class":"cm_info_box"}).find_all(["dt","dd"])
# 위 처럼 하면 두가지를 동시에 찾을수가 있다.
for data in datas:
info=data.text
datas=soup.find("ul",attrs={"class":"grid_box _exterior _list"}).find_all("li",attrs={"class":"item _item"})
#아래는 이미지 주소와 url 주소를 찾는 예제다.
for data in datas:
if data.find("img"):
img_src=data.find("img")["src"]
if data.find("a"):
url=data.find("a")["href"]
find 를 사용해서 데이터를 추출하는 예제2
아래는 requests 를 이용해서 데이터를 크롤링했을경우의 예제다.
특히 주목해야 할부분은
items=soup.find_all("li", attrs={"class":re.compile("^_itemSection")})
요기 인데
"^_itemSection" 는 클래스 이름이 _itemSection 로 시작하는것을 모두 찾으라는 뜻이다. 정규식을 사용하는 방법이다.
크롤링에서 유일하게 많이 사용되는 정규식이니 알아두면 종종 사용하게 될것이다.
import requests
import re
from bs4 import BeautifulSoup
import csv
url = "https://search.shopping.naver.com/best100v2/detail.nhn?catId=50004603"
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"}
res = requests.get(url, headers=headers)
res.raise_for_status()
soup = BeautifulSoup(res.text,'html.parser')
items=soup.find_all("li", attrs={"class":re.compile("^_itemSection")})
powerbanklist = [] # 라스트 생성
for item in items:
temp = []
name = item.find("a")["title"]#제품명
price = item.find("span", attrs = {"class":"num"}).get_text() #가격
link = item.find("div", attrs={"class":"thumb_area"}).find("a")["href"] #링크
review_number = item.find("span",attrs = {"class":"mall"}).find("em").text #리뷰수
review_number = review_number[1:-1]
temp.append(name)
temp.append(link)
temp.append(price)
temp.append(review_number)
powerbanklist.append(temp)
# print(notebooklist[0])
with open('powerbanklist.csv',"w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(['품명','링크','가격','리뷰수'])
writer.writerows(powerbanklist)
f.close
select 를 사용해서 데이터를 추출하는 예제
soup = BeautifulSoup(res.text,'html.parser')
items=soup.select("#productListArea > ul > li")
powerbanklist = [] # 라스트 생성
#print(items)
for item in items:
temp=[]
name = item.select_one("#productListArea > ul > li > p > a")["title"]
price = item.select_one("#productListArea > ul > li > div.price > strong > span.num").text
link = item.select_one("#productListArea > ul > li > p > a")["href"]
review_number = item.select_one("#productListArea > ul > li > div.info > span > a.txt > em").text
review_number = review_number[1:-1]
# print (review_number)
temp.append(name)
temp.append(link)
temp.append(price)
temp.append(review_number)
powerbanklist.append(temp)
select 를 사용하면 좀더 편리하게 코딩이 가능하다.
개발자모드에 들어간후 원하는 요소에다 마우스 우클릭후 copy selector 를 클릭하면 select 주소가 복사가된다.
select_one 은 첫번째 요소만 반환되고
select 를 사용하면 여러개가 리스트로 반환된다.
find_element 를 이용해서 데이터를 추출하는 방법
from selenium.webdriver.common.by import By
driver.find_element(By.XPATH, '//button[text()="Some text"]')
driver.find_element(By.XPATH, '//button')
driver.find_element(By.ID, 'loginForm')
driver.find_element(By.LINK_TEXT, 'Continue')
driver.find_element(By.PARTIAL_LINK_TEXT, 'Conti')
driver.find_element(By.NAME, 'username')
driver.find_element(By.TAG_NAME, 'h1')
driver.find_element(By.CLASS_NAME, 'content')
driver.find_element(By.CSS_SELECTOR, 'p.content')
# DOM의 하위집합 평가
fruits = driver.find_element(By.ID, "fruits")
fruit = fruits.find_element(By.CLASS_NAME,"tomatoes")
# 최적화 요소
fruit = driver.find_element(By.CSS_SELECTOR,"#fruits .tomatoes")
# 일치하는 모든 요소
plants = driver.find_elements(By.TAG_NAME, "li")
# 모든 요소 리스트에서 각 요소 가져오기
elements = driver.find_elements(By.TAG_NAME, 'p')
for e in elements:
print(e.text)
# 요소에서 요소찾기
element = driver.find_element(By.TAG_NAME, 'div')
elements = element.find_elements(By.TAG_NAME, 'p')
for e in elements:
print(e.text)
# 요소에서 속성값을 얻기
elements = browser.find_elements(By.TAG_NAME, 'a')
for element in elements:
print(element.get_attribute('href'))
elements = browser.find_elements(By.TAG_NAME, 'img')
for element in elements:
print(element.get_attribute('src'))
# 활성 요소 (현재 포커스가 있는)
attr = driver.switch_to.active_element.get_attribute("title")
알아두면 좋은 정보
텍스트 추출했을때 줄바꿈이 안되어 있을때
requst_lyrics = soup.select('div.show_lyrics')
for i in requst_lyrics:
s=i.get_text()
print(s)
위와 같이 텍스트만 추출했다고 가정해보자.
근데 텍스트가 줄바꿈이 적용이 안되어서 보기가 너무 어려운 경우가 생기기도 한다.
왜냐하면 중간중간 <br/> 태그가 있는데 이게 무시되기 때문인것 같다.
이럴때 해결방법이다.
requst_lyrics = soup.select('div.show_lyrics')
for i in requst_lyrics:
s=str(i)
s = s[40:]
s = s[:-6]
s = s.replace('<br/>', '\n')
print(s)
웹엘리먼트 요소를 문자로 타입변경한후 필요없는 부분 잘라내고 <br/> 태그를 줄바꿈으로 변경했다.
이것도 알아두면 유용할것이다.
STRING 으로 문자 추출하기
텍스트가 포함된 태그를 찾을때 유용하다. 이것은 정규식을 이용해서 특정단어를 포함하는 문자 찾기나 시작하는 문자 찾기를 이용하면 좋은 결과를 얻을수있을듯하다.
soup.title.find_all(string=True)
soup.title(string=True)
# 스트링이 있는 title 태그 모두 검색
soup.find_all(string="Elsie")
# [u'Elsie']
soup.find_all(string=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']
soup.find_all(string=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story2"]
#Dormouse 를 포함하는 스트링 찾기
soup.find_all(string=is_the_only_string_within_a_tag)
# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']
soup.find_all("a", string="Elsie")
# [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]
인풋박스에 내용입력이 안될때 아래 방법으로 해결 (ActionChains)
from selenium.webdriver.common.action_chains import ActionChains
html = "내용"
browser.find_element(By.CSS_SELECTOR, 'textarea.KHxj8b.tL9Q4c').click()
time.sleep(0.5)
action = ActionChains(browser)
action.send_keys(html).perform()
ActionChains 을 사용해서 아이디와 비번을 입력하고 로그인버튼을 누르는 예제
send_keys 를 이용해서 내용 입력하는것이 안될때 ActionChains 을 이용하면 가능한 경우가 많았다.
from selenium.webdriver.common.action_chains import ActionChains
# 사용자 동작에 필요한 웹 요소들 찾기
actions = ActionChains(driver)
actions.send_keys_to_element(id_box, 'str1')
actions.send_keys_to_element(pw_box, 'str2')
actions.click(login_button)
actions.perform()
문자열에서 특수문자를 제거하는 방법 , 숫제만 제거, 숫자만 추출 방법
정규식을 사용해서 특수문자를 없애는 방법입니다. 크롤링한 제목을 이용해서 폴더이름을 생성할때 특수문자가 있어서 폴더를 만들수 없다는 에러가 나올때가 있습니다. 이럴때 사용하면 좋습니다.
import re
#특수문자 제거
str = "AA**BB#@$CC 가나다-123"
new_str = re.sub(r"[^\uAC00-\uD7A30-9a-zA-Z\s]", "", str)
print(new_str)
#Output:AABBCC 가나다123
#숫자만 남기기
new_str = re.sub(r"[^0-9]", "", string)
print(new_str)
#Output:123
#숫자만 제거
new_str = re.sub(r"[0-9]", "", string)
print(new_str)
#Output:AA**BB#@$CC 가나다-
아래는 한글만 추출하는 예제입니다.
import re
my_str = "안녕하세요 ㅎㅎ. Hello World! 12345?"
kor_str = re.sub(r"[^ㄱ-ㅣ가-힣\s]", "", my_str) # 한글 + 공백만 남기기
not_kor_str = re.sub(r"[ㄱ-ㅣ가-힣]", "", my_str) # 한글만 제거하기
not_zamo_str = re.sub(r"[^가-힣]", "", my_str) # 자모가 아닌 한글만 남기기(공백 제거)
print(kor_str) # 안녕하세요 ㅎㅎ
print(not_kor_str) # . hello world! 12345?
print(not_zamo_str) # 안녕하세요
아래는 영문만 추출하는 예제입니다.
import re
my_str = "안녕하세요 ㅎㅎ. Hello World! 12345?"
eng_str = re.sub(r"[^a-zA-Z\s]", "", my_str) # 영문자 + 공백만 남기기
not_eng_str = re.sub(r"[a-zA-Z]", "", my_str) # 영문자만 제거하기
lower_eng_str = re.sub(r"[^a-z]", "", my_str) # 소문자만 남기기
print(eng_str) # Hello World
print(not_eng_str) # 안녕하세요 ㅎㅎ. ! 12345?
print(lower_eng_str) # elloorld
'파이썬' 카테고리의 다른 글
썸네일 이미지 자동으로 만들기 / 파이썬 / webp (0) | 2022.11.29 |
---|
댓글