TIL - HTML ๋ถ์
๐ย ๊ณต๋ถ ๋ด์ฉ
requests
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ์น ๋ธ๋ผ์ฐ์ ์ ๊ฐ์ด ์น ํ์ด์ง๋ฅผ ์์ฒญํ๊ณ ์๋ต์ ๋ฐ์์ด
- ์๋ต ๋ฐ์ ๋ฌธ์ -> ๋ถ์ ํ์!
BeautifulSoup
HTML ์ฝ๋๋ฅผ ๋ถ์ ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (HTML Parser)
์ค์น ๋ฐฉ๋ฒ
(mac, python3 ๊ธฐ์ค)
|
|
HTML ๋ถ์ ์ค์ต
ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ถ๋ฌ์ค๊ธฐ
1 2
import requests from bs4 import BeautifulSoup #import bs library
์ฌ์ดํธ๋ฅผ ์์ฒญํ๊ณ ์๋ต๋ฐ๊ธฐ
1 2
# requests.get์ผ๋ก ์ฌ์ดํธ HTML์ ๋ฐ์ ์ ์ ์ฅ res = requests.get("https://www.example.com")
์๋ต๋ฐ์ HTML์ผ๋ก BeautifulSoup ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ๋ด์ฉ์ ์ถ๋ ฅํด๋ณด๊ธฐ
1 2 3 4 5 6
# bs ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ , res.text์ "html.paser"๋ฅผ ์ธ์๋ก ๋๊ฒจ # HTML parser ์ญํ ์ ํ๊ฒ ๋ง๋ฌ soup = BeautifulSoup(res.text, "html.parser") # HTML์ ๊ตฌ์กฐ๋ฅผ ์ ๋ณด์ฌ์ฃผ๋๋ก ๋ค์ฌ์ฐ๊ธฐํ์ฌ ์ถ๋ ฅ print(soup.prettify())
HTML์ ํน์ ์์ ์ฐพ๊ธฐ
1 2 3 4 5 6 7 8 9 10 11 12 13
# ํด๋นํ๋ ๊ฐ ํ๊ทธ์ ๋ด์ฉ์ ๋ณด์ฌ์ค soup.title soup.head soup.body # h1ํ๊ทธ๋ค ์ค ๊ฐ์ฅ ๋จผ์ ๋์ค๋๊ฒ์ ์ฐพ์ ๋ฐํ h1 = soup.find("h1") # pํ๊ทธ ๋ชจ๋๋ฅผ ์ฐพ์ ๋ฐํ soup.find_all("p") # ํ๊ทธ ์ด๋ฆ๊ณผ (h1) ํ๊ทธ ์์ ๋ด์ฉ์ ๊ฐ์ ธ์ด h1.name h1.text
ํน์ ์์๋ฅผ ์ฐพ์ ๊ทธ ์์ ์ํ๋ ์ ๋ณด๋ง ์ถ๋ ค๋ด๊ธฐ
1 2 3 4 5 6 7 8 9
# ์ฑ ๋ฆฌ์คํธ๋ฅผ ์ฐพ์ ๊ทธ ์ ๋ชฉ๋ง ์ถ์ถํ๋ ์ฝ๋ # ์ง์ ์ฌ์ดํธ๋ฅผ ํ์ธํ๊ณ h3ํ๊ทธ์ ์ฑ ์ด๋ฏธ์ง, ์ ์, ์ ๋ชฉ ๋ฑ์ด ์๋๊ฒ์ ํ์ธํ์ฌ find_all๋ก ๊ฐ์ ธ์ด h3_results = soup.find_all('h3') # ๊ฐ์ฒด๋ก ๋ง๋ค๊ฒ ๋๋ฉด, ๋ด๋ถ ํ๊ทธ๋ฅผ ์์ฑ์ฒ๋ผ ์ธ ์ ์์ # h3 > a ํ๊ทธ ๋ด์ title ์์ฑ value๋ฅผ ์ถ๋ ฅํ๋ ํจ์ for book in h3_results: print(book.a['title'])
id
๋ฅผ ์ด์ฉํด ์์ ๊ฐ์ ธ์ค๊ธฐ1 2 3
# .find(<tag_name>, id = <id_name>) soup.find_all("div", id="bo_list") soup.find("div", id="bo_cate")
class
๋ฅผ ์ด์ฉํด ์์ ๊ฐ์ ธ์ค๊ธฐ1 2 3
# .find(<tag_name>, <class_name>) soup.find_all("li", "questions") soup.find("div", "question")
user-agent
์ ๋ณด๋ฅผ ๋๊ธฐ๋ฉด์ ์์ฒญํ๊ธฐ
user agent ํ์ธ ์ฌ์ดํธ1 2 3 4 5
user_agent = {"User-Agent": <๋ณธ์ธ์ user agent ์ ๋ณด>} import requests from bs4 import BeautifulSoup url = "https://qna.programmers.co.kr/" res = requests.get(url, user_agent)
ํ์ด์ง๋ค์ด์ (Pagination)
์ ๋ณด๋ฅผ ์ธ๋ฑ์ค๋ก ๊ตฌ๋ถํ๋ ๊ธฐ๋ฒ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# ํด๋น ์ฌ์ดํธ๋ query string์ผ๋ก ๊ตฌ๋ถ import time import requests from bs4 import BeautifulSoup url = "https://qna.programmers.co.kr/?page={}" for i in range(1, 6): res = requests.get(url.format(i), user_agent) soup = BeautifulSoup(res.text, "html.parser") questions = soup.find_all("li", "question-list-item") for question in questions: print(question.find("div", "question").find("div", "top").h4.a.text) # ๊ณผ๋ํ ์์ฒญ์ ๋ฐฉ์งํ๊ธฐ ์ํด 1์ด๋ง๋ค ์์ฒญ time.sleep(1)
์น ์ฌ์ดํธ์ ์คํฌ๋ํ
์ ์ or ๋์ ์น ์ฌ์ดํธ
- ์น ์ฌ์ดํธ๋ ์ ์ (Static) ์น ์ฌ์ดํธ ์ ๋์ (Dynamic) ์น ์ฌ์ดํธ ๋ก ๋๋ ์ ์๋ค.
์น ์ฌ์ดํธ Static Dynamic HTML ๋ด์ฉ ๊ณ ์ ๋ณ๊ฒฝ HTML ๋ฐ์ดํฐ ๋ก๋ ์๋ต ์ด์ ์ ์๋ฃ๋จ ์๋ต ์ดํ์ ์๋ฃ๋๊ธฐ๋ ํจ
๋๊ธฐ or ๋น๋๊ธฐ ์ฒ๋ฆฌ
๋๊ธฐ ์ฒ๋ฆฌ (์ ์ ์น ์ฌ์ดํธ)
- ๋ ๋๋ง์ด ์๋ฃ๋ ์ดํ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์งํ
- ์์ฒญ์ ๋ฐ๋ฅธ ์๋ต์ ๊ธฐ๋ค๋ ค์ผ ํจ
๋น๋๊ธฐ ์ฒ๋ฆฌ (๋์ ์น ์ฌ์ดํธ)
- ๋ ๋๋ง๊ณผ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊ฐ ๋์์ ์งํ๋จ
- ์์ฒญ์ ๋ฐ๋ฅธ ์๋ต์ ๊ธฐ๋ค๋ฆฌ์ง ์์
- ์ํฉ์ ๋ฐ๋ผ ์๋ต ์ ๋ฐ์ HTML ๋ฌธ์์ ๋ฐ์ดํฐ๊ฐ
์์ ํ์ง ์์ ๊ฒฝ์ฐ ๋ฐ์
์คํฌ๋ํ
requests ์์ฒญ์ ๋ฌธ์ ์
- ๋ถ์์ ํ๊ณ ์ํ์ง ์์ ๋ด์ฉ์ ์๋ต์ ๋ฐ๊ฒ ๋์ด ๋์ ์น์ฌ์ดํธ์ ์ ์ฉ์ด ์ด๋ ค์
- ํค๋ณด๋, ๋ง์ฐ์ค ์ ๋ ฅ ๋ฑ UI์ ์ํธ์์ฉ ํ๊ธฐ ์ด๋ ค์
ํด๊ฒฐ ๋ฐฉ๋ฒ
- ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ ์๋ต์ ๋ฐ์์ค๋ ๋ฐฉ์ ์ ์ฉ
- UI Action์ ํ๋ก๊ทธ๋๋ฐ
- ์น ๋ธ๋ผ์ฐ์ ์ญํ ์ ํ๋ ๋์ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์กฐ์ ->
Selenium
๐ย CHECK
(์ด๋ ต๊ฑฐ๋ ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ ๋ฑ ๋ค์ ํ์ธํ ๊ฒ๋ค)
- Pagination : ์ ๋ณด๋ฅผ ์ธ๋ฑ์ค๋ก ๊ตฌ๋ถํ๋ ๊ธฐ๋ฒ
- Query String
- .format method
1
"{}".format(a) -> "a"
- ๋๊ธฐ ์ฒ๋ฆฌ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๊ฐ๋ ์ ๋ํด ํ๋ฒ ๋ ๋ณต์ต
- bs .find ํจ์
- ์ฌ๋ฌ ์์๋ฅผ ์ฐพ์ ๋ or์ ์ ์ฉํ์ฌ A or B or C class ๋ชจ๋๋ฅผ ์ฐพ์ ์ ์๋์ง ๊ถ๊ธ
- class A, B / class A ์ธ ์์ ๋ ๊ฐ๊ฐ ์์ ๋ class B๋ฅผ ๊ฐ์ง ์์๋ ๋ฐฐ์ ํ๊ณ ์ฐพ๋ ๋ฐฉ๋ฒ๋ ๊ถ๊ธ
- ์ ์ ์น ์ฌ์ดํธ์๋ requests๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ๊ณ ๋์ ์น ์ฌ์ดํธ์๋ Selenium์ ์ฐ๋์ง ์๋๋ฉด ์ผ๊ด์ ์ผ๋ก Selenium์ฒ๋ผ ์น ์ฌ์ดํธ๋ฅผ ์กฐ์ํ๋ ํ์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ์ฐ๋์ง ๊ถ๊ธํ๋ค.
- ์ค์ฒฉ๋ div ๋ด์ h4๊ฐ ์๋ ๊ฒฝ์ฐ์ (div>div>h4) ๊ฐ์ฅ ๋ฐ๊นฅ div ๋ด์ h4๊ฐ ํ๋๋ฟ์ด๋ผ๋ฉด
div_container.find("div").h4
๋ก ์ฐ์ง ์๊ณdiv_container.h4
๋ก ์์ฑํด๋ ์ํ๋ ๊ธฐ๋ฅ์ ํ๋๋ฐ ์ด์ ๊ฐ ๊ถ๊ธํ๋ค.
โย ๋๋ ์
์ค๋์ ๊ฝค๋ ๋ง์กฑ์ค๋ฌ์ด ํ๋ฃจ๋ฅผ ๋ณด๋๋ค.
๊ฐ์์ ์ค์ต์ ๋ด ๊ธฐ์ค์ ์ด๋ ต์ง ์์ 2์๊ฐ ๋ด๋ก ์๋ฃํ๋ค. ์ค์ต์ ํ๋ฉด์ ์ฃผ์ด์ง ์ฌ์ดํธ ์ธ์ ๋ค๋ฅธ ์ฌ์ดํธ๋ ๋ค์ด๊ฐ์ ๋ถ์ํ๊ณ ๋ฐฐ์ด ํจ์๋ฅผ ์ ์ฉํด๋ณด์๋ค. ์ค์ต์ ํ๋ฉด์ ๊ถ๊ธํ ์ ์ด ๋ช๊ฐ ์๊ฒผ๊ณ CHECK์๋ ์ ์ด๋จ๋๋ฐ, TIL์ ๋ค ์ ์ ํ์ ๊ตฌ๊ธ๋ง ๋ฐ ์ฌ๋ ์ฑ๋์ ํตํด์ ํด๊ฒฐํด ๋ณผ ์๊ฐ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ์ฝ์ดํ์ ์ค๊ฐ์ hugo๋ก ๋ง๋ ๋ธ๋ก๊ทธ์ ๊ธ์ ์ฌ๋ ค๋ดค๋๋ฐ ๋ด๊ฐ ์๊ฐํ๋๊ฒ ๋ณด๋ค ๋ ์ฌ์์ ์์ฌํ๋ค. ๋ธ๋ก๊ทธ์ ๊ด๋ จํด ๋ค์ ์ธ ๊ฐ์ง ๋ชฉํ๋ฅผ ์ธ์ ๋ค.
- github action ์์ ํด์ push ํ๋ฉด ์๋์ผ๋ก ๋น๋, ๋ฐฐํฌ๋๊ฒ ๋ง๋ค๊ธฐ
- hugo new post ํ ํ๋ฆฟ ๋ง๋ค๊ธฐ
- ํ๊ตญ์ด ์ค์ ํ๊ธฐ
์ด๋ ๊ฒ ์ธํ ์ ์๋ฃํ ํ์, ๊ธฐ์กด์ ์์ฑํ๋ TIL์ ์ฌ๋ฆฌ๊ณ ์นดํ ๊ณ ๋ฆฌ ์ค์ ๊น์ง ํ๋ฉด ์์ฑ์ด๋ค. ๋์ค์ ๋ธ๋ก๊ทธ ๋ฉ์ธ ํ์ด์ง ์ปค์คํ , ๋๊ธ ์์ ฏ ์ค์ , SEO ์ธํ ๋ฑ์ ํด๋ณด๋ ค๊ณ ํ๋ค.