• python 爬虫热身篇 使用 requests 库通过 HTTP 读取网络数据,使用 pandas 读取网页上的表格,使用 Selenium 模拟浏览器操作


    引言

    在过去,收集数据是一项繁琐的工作,有时非常昂贵。机器学习项目不能没有数据。幸运的是,我们现在在网络上有很多数据可供我们使用。我们可以从 Web 复制数据来创建数据集。我们可以手动下载文件并将其保存到磁盘。但是,我们可以通过自动化数据收集来更有效地做到这一点。Python中有几种工具可以帮助自动化。

    完成本教程后,您将学习:

    • 如何使用 requests 库通过 HTTP 读取网络数据
    • 如何使用 pandas 读取网页上的表格
    • 如何使用 Selenium 模拟浏览器操作

    概述

    本教程分为三个部分;它们是:

    • 使用 requests
    • 使用 panda 在网络上阅读表格
    • selenium 阅读动态内容

    使用requests

    当我们谈论编写Python程序从Web上读取时,不可避免的是我们无法避免requests库。您需要安装它(以及我们稍后将介绍的BeautifulSoup和lxml):

    pip install requests beautifulsoup4 lxml
    
    • 1

    它为您提供了一个界面,可让您轻松与网络进行交互。

    非常简单的用例是从URL读取网页:

    import requests
    
    # Lat-Lon of New York
    URL = "https://weather.com/weather/today/l/40.75,-73.98"
    resp = requests.get(URL)
    print(resp.status_code)
    print(resp.text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D0BjRF5c-1659953141850)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1b62c0be6a0a4d75808b9db6816f4240~tplv-k3u1fbpfcp-watermark.image?)]

    如果您熟悉 HTTP,您可能还记得状态代码 200 表示请求已成功完成。然后我们可以阅读响应。在上面,我们阅读文本响应并获取网页的HTML。如果它是CSV或其他一些文本数据,我们可以在响应对象的属性中获取它们。例如text,这就是我们从美联储经济学数据中读取CSV的方法:

    以下例子会用到pandas 模块 :

    安装: pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple

    import io
    import pandas as pd
    import requests
    
    URL = "https://fred.stlouisfed.org/graph/fredgraph.csv?id=T10YIE&cosd=2017-04-14&coed=2022-04-14"
    resp = requests.get(URL)
    if resp.status_code == 200:
       csvtext = resp.text
       csvbuffer = io.StringIO(csvtext)
       df = pd.read_csv(csvbuffer)
       print(df)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行结果:

    在这里插入图片描述

    如果数据是JSON的形式,我们可以将其读取为文本,甚至可以为您解码。例如,以下是以JSON格式从GitHub中提取一些数据并将其转换为Python字典:

    import requests
    
    URL = "https://api.github.com/users/jbrownlee"
    resp = requests.get(URL)
    if resp.status_code == 200:
        data = resp.json()
        print(data)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:

    在这里插入图片描述

    但是,如果 URL 为您提供了一些二进制数据,例如 ZIP 文件或 JPEG 图像,则需要在属性中获取它们,因为这将是二进制数据。例如,这就是我们下载图像(维基百科的标志)的方式:

    import requests
    
    URL = "https://en.wikipedia.org/static/images/project-logos/enwiki.png"
    wikilogo = requests.get(URL)
    if wikilogo.status_code == 200:
        with open("enwiki.png", "wb") as fp:
            fp.write(wikilogo.content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:

    在这里插入图片描述

    鉴于我们已经获得了网页,我们应该如何提取数据?这超出了requests所能提供给我们的范围,但我们可以使用不同的library 来提供帮助。有两种方法可以做到这一点,这取决于我们想要如何指定数据。

    第一种方法是将 HTML 视为一种 XML 文档,并使用 XPath 语言提取元素。在这种情况下,我们可以利用该库首先创建一个文档对象模型(DOM),然后通过XPath进行搜索:

    import requests
    from lxml import etree
    
    
    
    URL = "https://weather.com/weather/today/l/40.75,-73.98"
    resp = requests.get(URL)
    
    # 从HTML文本创建DOM
    dom = etree.HTML(resp.text)
    # 搜索温度元素并获得内容
    elements = dom.xpath("//span[@data-testid='TemperatureValue' and contains(@class,'CurrentConditions')]")
    print(elements[0].text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    XPath 是一个字符串,它指定如何查找元素。lxml 对象提供了一个函数,用于在 DOM 中搜索与 XPath 字符串匹配的元素,这些元素可以是多个匹配项。上面的 XPath 意味着在具有标记和属性与 “” 匹配且以 “” 开头的任何位置查找 HTML 元素。我们可以通过检查HTML源代码从浏览器的开发人员工具(例如,下面的Chrome屏幕截图)中学习这一点。xpath()````data-testid``TemperatureValue``class``CurrentConditions

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Va6MrPxn-1659953141852)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/30e3014198a14cadaff47c6cea2cfd04~tplv-k3u1fbpfcp-watermark.image?)]

    这个例子是找到纽约市的温度,由我们从这个网页获得的这个特定元素提供。我们知道与 XPath 匹配的第一个元素是我们需要的,我们可以读取标记内的文本。

    另一种方法是在HTML文档上使用CSS选择器,我们可以利用BeautifulSoup库:

    import requests
    from bs4 import BeautifulSoup
    
    
    
    URL = "https://weather.com/weather/today/l/40.75,-73.98"
    resp = requests.get(URL)
    
    soup = BeautifulSoup(resp.text, "lxml")
    elements = soup.select('span[data-testid="TemperatureValue"][class^="CurrentConditions"]')
    print(elements[0].text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行结果:

    在这里插入图片描述

    在上面,我们首先将HTML文本传递给BeautifulSoup。BeautifulSoup支持各种HTML解析器,每个解析器具有不同的功能。在上面,我们使用库作为BeautifulSoup推荐的解析器(它通常也是最快的)。CSS选择器是一种不同的迷你语言,与XPath相比有优点和缺点。上面的选择器与我们在上一个示例中使用的 XPath 相同。因此,我们可以从第一个匹配的元素中获得相同的温度。

    以下是根据网络上的实时信息打印纽约当前温度的完整代码:

    import requests
    from bs4 import BeautifulSoup
    from lxml import etree
    
    
    URL = "https://weather.com/weather/today/l/40.75,-73.98"
    resp = requests.get(URL)
    
    if resp.status_code == 200:
        # Using lxml
        dom = etree.HTML(resp.text)
        elements = dom.xpath("//span[@data-testid='TemperatureValue' and contains(@class,'CurrentConditions')]")
        print(elements[0].text)
    
        # Using BeautifulSoup
        soup = BeautifulSoup(resp.text, "lxml")
        elements = soup.select('span[data-testid="TemperatureValue"][class^="CurrentConditions"]')
        print(elements[0].text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    可以想象,您可以通过定期运行此脚本来收集温度的时间序列。同样,我们可以从各种网站自动收集数据。这就是我们为机器学习项目获取数据的方法。

    使用 panda 在网络上阅读表格

    通常,网页将使用表格来承载数据。如果页面足够简单,我们甚至可以跳过检查它以找出XPath或CSS选择器,并使用pandas一次性获取页面上的所有表格。它很简单,可以在一行中完成:

    import pandas as pd
    
    tables = pd.read_html("https://www.federalreserve.gov/releases/h10/current/")
    print(tables)
    
    • 1
    • 2
    • 3
    • 4
    [                               Instruments 2022Apr7 2022Apr8 2022Apr11 2022Apr12 2022Apr13
    0          Federal funds (effective) 1 2 3     0.33     0.33      0.33      0.33      0.33
    1                 Commercial Paper 3 4 5 6      NaN      NaN       NaN       NaN       NaN
    2                             Nonfinancial      NaN      NaN       NaN       NaN       NaN
    3                                  1-month     0.30     0.34      0.36      0.39      0.39
    4                                  2-month     n.a.     0.48      n.a.      n.a.      n.a.
    5                                  3-month     n.a.     n.a.      n.a.      0.78      0.78
    6                                Financial      NaN      NaN       NaN       NaN       NaN
    7                                  1-month     0.49     0.45      0.46      0.39      0.46
    8                                  2-month     n.a.     n.a.      0.60      0.71      n.a.
    9                                  3-month     0.85     0.81      0.75      n.a.      0.86
    10                   Bank prime loan 2 3 7     3.50     3.50      3.50      3.50      3.50
    11      Discount window primary credit 2 8     0.50     0.50      0.50      0.50      0.50
    12              U.S. government securities      NaN      NaN       NaN       NaN       NaN
    13   Treasury bills (secondary market) 3 4      NaN      NaN       NaN       NaN       NaN
    14                                  4-week     0.21     0.20      0.21      0.19      0.23
    15                                 3-month     0.68     0.69      0.78      0.74      0.75
    16                                 6-month     1.12     1.16      1.22      1.18      1.17
    17                                  1-year     1.69     1.72      1.75      1.67      1.67
    18            Treasury constant maturities      NaN      NaN       NaN       NaN       NaN
    19                               Nominal 9      NaN      NaN       NaN       NaN       NaN
    20                                 1-month     0.21     0.20      0.22      0.21      0.26
    21                                 3-month     0.68     0.70      0.77      0.74      0.75
    22                                 6-month     1.15     1.19      1.23      1.20      1.20
    23                                  1-year     1.78     1.81      1.85      1.77      1.78
    24                                  2-year     2.47     2.53      2.50      2.39      2.37
    25                                  3-year     2.66     2.73      2.73      2.58      2.57
    26                                  5-year     2.70     2.76      2.79      2.66      2.66
    27                                  7-year     2.73     2.79      2.84      2.73      2.71
    28                                 10-year     2.66     2.72      2.79      2.72      2.70
    29                                 20-year     2.87     2.94      3.02      2.99      2.97
    30                                 30-year     2.69     2.76      2.84      2.82      2.81
    31                    Inflation indexed 10      NaN      NaN       NaN       NaN       NaN
    32                                  5-year    -0.56    -0.57     -0.58     -0.65     -0.59
    33                                  7-year    -0.34    -0.33     -0.32     -0.36     -0.31
    34                                 10-year    -0.16    -0.15     -0.12     -0.14     -0.10
    35                                 20-year     0.09     0.11      0.15      0.15      0.18
    36                                 30-year     0.21     0.23      0.27      0.28      0.30
    37  Inflation-indexed long-term average 11     0.23     0.26      0.30      0.30      0.33,  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    pandas 中的函数read_html()读取 URL 并查找页面上的所有表。每个表都转换为 pandas DataFrame,然后在列表中返回所有表。在这个例子中,我们正在阅读美联储的各种利率,而美联储恰好在这个页面上只有一个表格。表列由 pandas 自动标识。

    很可能并非所有表格都是我们感兴趣的。有时,网页会使用表格作为格式化页面的一种方式,但熊猫可能不够聪明, 无法分辨。因此,我们需要测试并挑选函数返回的结果。

    用硒阅读动态内容

    现代网页的很大一部分充满了JavaScript。这给了我们一个更奇特的体验,但成为一个障碍,用作提取数据的程序。一个例子是雅虎的主页,如果我们只加载页面并找到所有新闻标题,那么在浏览器上看到的要少得多:

    import requests
    
    # Read Yahoo home page
    from lxml import etree
    
    URL = "https://www.yahoo.com/"
    resp = requests.get(URL)
    dom = etree.HTML(resp.text)
    
    # Print news headlines
    elements = dom.xpath("//h3/a[u[@class='StretchedBox']]")
    for elem in elements:
        print(etree.tostring(elem, method="text", encoding="unicode"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行结果:

    在这里插入图片描述

    这是因为像这样的网页依靠JavaScript来填充内容。著名的Web框架,如AngularJS或React,是这一类别的幕后推手。Python 库,比如requests ,不理解 JavaScript。因此,您将看到不同的结果。如果你想从网上获取的数据就是其中之一,你可以研究JavaScript是如何被调用的,并在你的程序中模仿浏览器的行为。但这可能太乏味了,无法使其正常工作。

    另一种方法是要求真正的浏览器读取网页,而不是使用requests。这就是selenium可以做的。在使用它之前,我们需要安装库:

    pip install selenium
    
    • 1

    Selenium只是一个控制浏览器的框架。您需要在计算机上安装浏览器以及将Selenium连接到浏览器的驱动程序。如果您打算使用Chrome,则还需要下载并安装ChromeDriver。您需要将驱动程序chromedriver放在可执行路径中,以便Selenium可以像普通命令一样调用它。

    同样,如果你使用的是Firefox,你需要GeckoDriver。有关设置Selenium的更多详细信息,请参阅其文档

    之后,您可以使用 Python 脚本来控制浏览器行为。例如:

    import time
    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    
    # Launch Chrome browser in headless mode
    options = webdriver.ChromeOptions()
    options.add_argument("headless")
    browser = webdriver.Chrome(options=options)
    
    # Load web page
    browser.get("https://www.yahoo.com")
    
    
    # Network transport takes time. Wait until the page is fully loaded
    def is_ready(browser):
        return browser.execute_script(r"""
            return document.readyState === 'complete'
        """)
    
    
    WebDriverWait(browser, 30).until(is_ready)
    
    # Scroll to bottom of the page to trigger JavaScript action
    browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(1)
    WebDriverWait(browser, 30).until(is_ready)
    
    # Search for news headlines and print
    elements = browser.find_elements(By.XPATH, "//h3/a[u[@class='StretchedBox']]")
    for elem in elements:
        print(elem.text)
    
    # Close the browser once finish
    browser.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    上述代码的工作原理如下。我们首先以无外设模式启动浏览器,这意味着我们要求Chrome启动但不显示在屏幕上。如果我们想远程运行脚本,这很重要,因为可能没有任何GUI支持。请注意,每个浏览器的开发方式都不同,因此我们使用的选项语法特定于Chrome。如果我们使用Firefox,代码将是这样的:

    options = webdriver.FirefoxOptions()
    options.set_headless()
    browser = webdriver.Firefox(firefox_options=options)
    
    • 1
    • 2
    • 3

    启动浏览器后,我们会为其提供一个要加载的 URL。但是,由于网络需要时间来交付页面,并且浏览器需要时间来呈现它,因此我们应该等到浏览器准备就绪后再继续下一个操作。我们检测浏览器是否已经使用 JavaScript 完成了渲染。我们让Selenium为我们运行JavaScript代码,并使用该函数告诉我们结果。我们利用Selenium的工具运行它,直到它成功或直到30秒超时。加载页面时,我们滚动到页面底部,以便可以触发JavaScript以加载更多内容。然后,我们无条件地等待一秒钟,以确保浏览器触发了JavaScript,然后等待页面再次准备就绪。之后,我们可以使用XPath(或者使用CSS选择器)提取新闻标题元素。由于浏览器是外部程序,因此我们负责在脚本中关闭它。

    使用硒在几个方面与使用库不同。首先,您永远不会直接在Python代码中拥有Web内容。相反,您可以在需要时引用浏览器的内容。因此,该函数返回的Web元素引用外部浏览器内部的对象,因此在完成使用它们之前,我们不得关闭浏览器。其次,所有操作都应基于浏览器交互而不是网络请求。因此,您需要通过模拟键盘和鼠标移动来控制浏览器。但作为回报,您拥有支持JavaScript的全功能浏览器。例如,您可以使用 JavaScript 检查页面上某个元素的大小和位置,只有在呈现 HTML 元素后,您才会知道这些大小和位置。

    Selenium框架提供了更多功能,我们可以在这里介绍。它功能强大,但是由于它连接到浏览器,因此使用它比库的要求更高,并且速度要慢得多。通常,这是从网络收集信息的最后手段。

    延伸阅读

    Python中另一个著名的Web爬行库,我们上面没有介绍过,那就是Scrapy。这就像将requests库与BeautifulSoup合并为一体一样。网络协议很复杂。有时我们需要管理网络 cookie 或使用 POST 方法为请求提供额外的数据。所有这些都可以通过具有不同函数或额外参数的请求库来完成。以下是一些资源供您深入了解:

  • 相关阅读:
    设计模式:解释器模式
    基于springboot的二手物品交易管理系统
    mysql数据库概述及安装
    qmake 手册:qmake 入门
    Vue配置代理,v-resource(ajax库)
    解决:Both vertex and fragment programs must be present in a CGPROGRAM
    Webpack
    手把手带你学SQL—牛客网SQL 别名
    最佳实践-LinkBlockingQueue改进
    tiup update
  • 原文地址:https://blog.csdn.net/a883774913/article/details/126233140