ZetCode

Python 网络爬虫

最后修改于 2024 年 1 月 29 日

在本文中,我们将展示如何在 Python 中进行网络抓取。 我们使用多个 Python 库。

网络抓取是从网页中获取和提取数据。 网络抓取用于收集和处理用于营销或研究的数据。 这些数据包括职位列表、价格比较或社交媒体帖子。

Python 是数据科学的常用选择。 它包含许多用于网络抓取的库。 要获取数据,我们可以使用 requestsurllib3 库。 如果我们想创建异步客户端,可以使用 httpx 库。

要处理数据,我们可以使用 lxmlpyquery 或 BeautifulSoup。 这些库适用于静态数据。 如果数据隐藏在 JavaScript 之后,我们可以使用 Selenium 或 PlayWright 库。

使用 urllib3 和 lxml 进行网络抓取

在第一个示例中,我们使用 urllib3 获取数据,并使用 lxml 处理数据。

main.py
#!/usr/bin/python

import urllib3
from lxml import html

http = urllib3.PoolManager()

url = 'http://webcode.me'
resp = http.request('GET', url)

content = resp.data.decode('utf-8')
root = html.fromstring(content)

print('------------------------')

print(root.head.find(".//title").text)

print('------------------------')

for e in root:
    print(e.tag)

print('------------------------')

print(root.body.text_content().strip())

该程序检索 HTML 标题、标签和 HTML 主体的文本内容。

http = urllib3.PoolManager()

创建一个 PoolManager。 它处理连接池和线程安全的所有细节。

url = 'http://webcode.me'
resp = http.request('GET', url)

我们向指定的 URL 生成一个 GET 请求。

content = resp.data.decode('utf-8')
root = html.fromstring(content)

我们获取并解码内容。 我们解析字符串以创建 lxml 的 HTML 文档。

print(root.head.find(".//title").text)

我们打印文档的标题。

for e in root:
    print(e.tag)

这里我们打印文档第一层的所有标签。

print(root.body.text_content().strip())

我们打印 HTML 主体的文本数据。

$ ./main.py 
------------------------
My html page
------------------------
head
body
------------------------
Today is a beautiful day. We go swimming and fishing.
    
    
    
         Hello there. How are you?

使用 requests 和 pyquery 进行网络抓取

在第二个示例中,我们使用 requests 库来获取数据,并使用 pyquery 来处理数据。

main.py
#!/usr/bin/python

from pyquery import PyQuery as pq
import requests as req

resp = req.get("http://www.webcode.me")
doc = pq(resp.text)

title = doc('title').text()
print(title)

pars = doc('p').text()
print(pars)

在该示例中,我们从所有 p 标签获取标题和文本数据。

resp = req.get("http://www.webcode.me")
doc = pq(resp.text)

我们生成一个 GET 请求,并从响应中创建一个可解析的文档对象。

title = doc('title').text()
print(title)

我们从文档中获取标题标签并打印其文本。

$ ./main.py
My html page
Today is a beautiful day. We go swimming and fishing. Hello there. How are you?

Python 抓取字典定义

在下一个示例中,我们从 dictionary.com 抓取单词的定义。 我们使用 requestslxml 库。

get_term.py
#!/usr/bin/python

import requests as req
from lxml import html
import textwrap

term = "dog"

resp = req.get("http://www.dictionary.com/browse/" + term)
root = html.fromstring(resp.content)

for sel in root.xpath("//span[contains(@class, 'one-click-content')]"):

    if sel.text:

        s = sel.text.strip()

        if (len(s) > 3):

            print(textwrap.fill(s, width=50))

该程序获取术语 dog 的定义。

import textwrap

textwrap 模块用于将文本包装到特定宽度。

resp = req.get("http://www.dictionary.com/browse/" + term)

要执行搜索,我们将术语附加到 URL 的末尾。

root = html.fromstring(resp.content)

我们需要使用 resp.content 而不是 resp.text,因为 html.fromstring 隐式地期望字节作为输入。 (resp.content 以字节形式返回内容,而 resp.text 以 Unicode 文本形式返回内容。)

for sel in root.xpath("//span[contains(@class, 'one-click-content')]"):

    if sel.text:

        s = sel.text.strip()

        if (len(s) > 3):

            print(textwrap.fill(s, width=50))

我们解析内容。 主要定义位于具有 one-click-content 属性的 span 标签内。 我们通过删除多余的空格和杂散字符来改进格式。 文本宽度最大为 50 个字符。 请注意,这种解析可能会发生变化。

$ ./get_term.py
a domesticated canid,
any carnivore of the dog family Canidae, having
prominent canine teeth and, in the wild state, a
long and slender muzzle, a deep-chested muscular
body, a bushy tail, and large, erect ears.
...

使用 BeautifulSoup 进行 Python 网络抓取

BeautifulSoup 是一个用于解析 HTML 和 XML 文档的 Python 库。 它是最强大的网络抓取解决方案之一。

BeautifulSoup 将复杂的 HTML 文档转换为复杂的 Python 对象树,例如 tag、navigable string 或 comment。

main.py
#!/usr/bin/python

from bs4 import BeautifulSoup
import requests as req

resp = req.get('http://webcode.me')

soup = BeautifulSoup(resp.text, 'lxml')

print(soup.title)
print(soup.title.text)
print(soup.title.parent)

在该示例中,我们获取标题标签、标题文本和标题标签的父标签。 为了获取网页,我们使用 requests 库。

soup = BeautifulSoup(resp.text, 'lxml')

创建一个 BeautifulSoup 对象; HTML 数据被传递给构造函数。 第二个选项指定内部解析器。

print(soup.title)
print(soup.title.text)
print(soup.title.parent)

我们使用内置属性获取数据。

$ ./main.py
<title>My html page</title>
My html page
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<link href="format.css" rel="stylesheet"/>
<title>My html page</title>
</head>

Python 抓取前 5 个国家/地区

在下一个示例中,我们提取人口最多的前 5 个国家/地区。

top_countries.py
#!/usr/bin/python

from bs4 import BeautifulSoup
import requests as req

resp = req.get('http://webcode.me/countries.html')

soup = BeautifulSoup(resp.text, 'lxml')

data = soup.select('tbody tr:nth-child(-n+5)')

for row in data:
    print(row.text.strip().replace('\n', ' '))

为了提取数据,我们使用 select 方法,该方法执行 CSS 选择操作。

$ ./top_countries.py 
1 China 1382050000
2 India 1313210000
3 USA 324666000
4 Indonesia 260581000
5 Brazil 207221000

Python 抓取动态内容

我们可以使用 PlayWright 或 Selenium 抓取动态内容。 在我们的示例中,我们使用 PlayWright 库。

$ pip install --upgrade pip
$ pip install playwright
$ playwright install

我们安装 PlayWright 和驱动程序。

main.py
#!/usr/bin/python

from playwright.sync_api import sync_playwright

with sync_playwright() as p:

    browser = p.chromium.launch()

    page = browser.new_page()
    page.goto("http://webcode.me/click.html")

    page.click('button', button='left')
    print(page.query_selector('#output').text_content())

    browser.close()

网页上只有一个按钮。 当我们点击按钮时,文本消息会出现在输出 div 标签中。

with sync_playwright() as p:

我们以同步模式工作。

browser = p.chromium.launch()

我们使用 chromium 浏览器。 浏览器是无头的。

page = browser.new_page()
page.goto("http://webcode.me/click.html")

我们导航到该页面。

page.click('button', button='left')

我们点击按钮。

print(page.query_selector('#output').text_content())

我们检索消息。

$ ./main.py 
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/109.0.5414.46 Safari/537.36

来源

Python Playwright 文档

在本文中,我们展示了如何在 Python 中进行网络抓取。

作者

我叫 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。到目前为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程