Bạn đang xem thử công khai
Đăng nhập để lưu tiến độ, làm bài tập, thảo luận và nhận phản hồi.
After this lesson you will: read the structure of an HTML page, use BeautifulSoup to extract data from it, and know when you should (or should not) scrape.
Web scraping means automatically pulling data out of web pages that are written for human readers. Prefer an API whenever the service offers one, because an API is more stable and follows the rules more closely. Scrape only when there is no API and collecting the data is allowed.
A web page is made of nested tags. Each tag can have attributes such as class, id, href:
<ul id="items">
<li class="item"><a href="/p/1">Pen</a> <span class="price">3.5</span></li>
</ul>
The example below uses a ready-made piece of HTML, so you can run it immediately without a network connection:
from bs4 import BeautifulSoup
html = """<html><body><h1>Shop</h1><ul id="items"><li class="item"><a href="/p/1">Pen</a> <span class="price">3.5</span></li><li class="item"><a href="/p/2">Book</a> <span class="price">12</span></li><li class="item sale"><a href="/p/3">Bag</a> <span class="price">20</span></li></ul></body></html>"""
soup = BeautifulSoup(html, "html.parser")
print(soup.h1.text) # Shop
print(len(soup.find_all("li"))) # 3 (every li tag)
print(soup.find("a")["href"]) # /p/1 (first a tag, read its href attribute)
print(soup.find_all("a")[1].get("href")) # /p/2
print(soup.find("table")) # None (find returns None when nothing matches)
find(...) returns the first matching element (or None); find_all(...) returns a list of all matching elements..text gets the text inside; ["href"] or .get("href") gets an attribute value. .get returns None instead of raising an error when the attribute is missing.select and select_oneThe syntax is the same as CSS: tag_name.class, #id, and a space to select a child tag.
print(len(soup.select("li.item"))) # 3
print(len(soup.select("li.sale"))) # 1 (only the item that also has class sale)
print(soup.select_one("li.sale a").text) # Bag
prices = [float(p.text) for p in soup.select("span.price")]
print(prices) # [3.5, 12.0, 20.0]
print(sum(prices)) # 35.5
Note: <li class="item sale"> has two classes, so it matches both li.item and li.sale. Extracted text is always a string, so you need float()/int() to do calculations.
import requests
resp = requests.get("https://books.toscrape.com/", timeout=10)
soup = BeautifulSoup(resp.text, "html.parser")
titles = [a["title"] for a in soup.select("article.product_pod h3 a")]
The site books.toscrape.com was built specifically for practicing scraping. Use it, and do not practice on other people's sites.
robots.txt (for example https://domain-name/robots.txt) and the site's terms of use before collecting data.time.sleep) so you do not overload the server.requests receives. In that case, look for the hidden API the page calls, or use a browser automation tool.find gives the first element, find_all gives a list; select/select_one use CSS selectors.robots.txt and the terms of use; wait between calls.Mitchell, R. (2018). Web Scraping with Python: Collecting Data from the Modern Web (2nd ed.). O'Reilly Media.