如何抓取网页数据(ESPN中获取棒球运动员公共网站下载数据的过程-乐题库)

优采云 发布时间: 2021-10-28 09:12

  如何抓取网页数据(ESPN中获取棒球运动员公共网站下载数据的过程-乐题库)

  网页抓取是从公共网站 下载数据的过程。例如,您可以从 ESPN 获取棒球运动员的统计数据,并构建一个模型,根据他们的球员统计数据和获胜率来预测球队获胜的机会。以下是网络抓取的一些用例。

  监控竞争对手的价格以进行价格匹配(竞争定价)。

  从各种 网站 采集统计信息以创建仪表板,例如 COVID-19 仪表板。

  监控金融论坛和 Twitter 以计算特定资产的情绪。

  我将演示的一个用例是抓取 网站 来发布招聘信息。假设您正在寻找工作,但您被列表的数量所淹没。您可以设置一个流程来实际每天抓取。然后你可以编写一个脚本来自动应用于满足特定条件的帖子。

  免责声明:网络抓取确实违反了他们的使用条款。本文仅用于教育目的。在抓取 网站 之前,请务必阅读他们的服务条款并遵循他们的 robots.txt 指南。

  数据仓库注意事项

  我们的蜘蛛每天都会抓取给定搜索查询可用的所有页面,因此我们想要存储大量重复项。如果帖子持续多天,那么我们将在帖子发布的每一天都有一份副本。为了容忍重复,我们将设计一个管道来捕获所有内容,然后过滤数据以创建可用于分析的标准化数据模型。

  首先会从网页中解析出数据,然后放入半结构化的数据结构中,比如JSON。从这里开始,数据结构将存储在对象存储中(例如 S3、GS)。对象存储是捕获数据的有用起点。它便宜、可扩展,并且可以通过我们的数据模型灵活更改。一旦数据进入我们的对象存储,网络爬虫的工作就完成了,数据也被捕获了。

  下一步是将数据非规范化为更有用的数据以供分析。如前所述,数据收录重复项。我会选择使用 SQL 数据库,因为它具有强大的分析查询功能。它还允许我区分不同的实体,例如公司、职位发布和地点。首先,所有帖子都会进入事实表(大型只写表),带有时间戳,显示帖子何时被抓取以及何时插入到表中。从这里,我们可以将数据非规范化为代表当前活动版本的有状态表。

  您可以编写合并语句来更新和插入表示实时发布的表中的发布。从这里我们还想删除已删除或过期的帖子。现在我们有了一个标准化的表,或者换句话说,所有的重复项都被删除了。

  设置项目

  对于这个项目,我将使用 Scrapy,因为它带有有用的特性和抽象,可以节省你的时间和精力。例如,scrapy 可以轻松地将结构化数据推送到 S3 或 GCS 等对象存储。这是通过将您的凭据以及存储桶名称和路径添加到由 scrapy 生成的配置文件来完成的。目的是为了长期存储并在我们每次运行刮刀时生成一个不可变的副本。由于 S3 是无限的对象存储,因此是长期存储的理想场所,并且可以轻松地随任何项目进行扩展。

  为了突出更多特性,scrapy 使用了 Twisted 框架来处理异步 web 请求。这意味着程序可以在等待网站服务器响应请求的同时完成它的工作,而不是因为空闲等待而浪费时间。Scrapy 有一个活跃的社区,因此您可以寻求帮助并查看其他项目的示例。它还提供了一些更高级的选项,例如在具有 Redis 和用户代理欺骗的集群中运行,但这些不在本教程的范围内。

  让我们从在 python 中创建一个虚拟环境并安装依赖项开始。然后初始化一个空白项目,我们将在其中安装我们的网络爬虫。请务必在项目的顶级目录中执行此代码。

  python3 -m venv venv

  源 ./venv/bin/activate

  pip install scrapy lxml BeautifulSoup4 jupyterlab pandas

  scrapy startproject 工作

  cd 工作/工作/

  确实是scrapy genspider

  解析网页的代码将被放置在蜘蛛/目录中的文件中。蜘蛛是网络爬虫的抽象。它生成 HTTP 请求并解析返回的页面。有一个单独的抽象用于处理和存储称为 ItemPipeline 的信息。这种抽象分离允许解耦、灵活性和水平扩展。比如,你可以在不修改蜘蛛代码内部逻辑的情况下,将蜘蛛的结果发送到多个地方。一个好的做法是将结果作为文件保存在对象存储中进行长期存储,并将其保存在数据库中进行重复数据删除和临时查询。

  开发环境

  您可以将网络抓取视为对他人工作的逆向工程。有许多工具可以使 Web 开发更易于组装和管理,例如使用可重用模板或 ES6 模块。这些允许 Web 开发人员在多个地方重用相同的代码,目标是将简单的部分组合成更复杂的部分。当您抓取网站 时,您所拥有的只是实际的网页,我们无法访问用于构建页面的组件。因此,我们必须向后工作以使用我们可以使用的任何技术来获得我们想要的东西。

  任何网络抓取项目的第一步都是在网络浏览器中打开要抓取的页面,然后使用“检查元素”在您选择的浏览器中探索 DOM。使用浏览器中的开发者工具,您可以探索 DOM 的结构或页面的骨架。现在您可以随意打开页面,使用开发者工具进行探索。在整个过程中,我们将使用浏览器以可视化和交互的方式快速浏览dom。

  我喜欢使用带有 iPython 的 scrapy shell 来为我的网页抓取开发解析代码。交互性允许快速反馈循环,允许大量试验和错误。scrapy shell 带您进入已实例化的所有帮助程序和便利函数的 scrapy 上下文。这些相同的对象在运行时可供蜘蛛使用。它还使您可以访问 iPython 的所有功能。您可以使用以下代码来启动您的 shell。

  scrapy shell',-MA-jobs.html'

  这里最重要的对象是响应。这收录从 Web 服务器到我们的 HTTP GET 请求的 HTTP 响应。它收录页面的 HTML,以及与 HTTP 响应相关的标头和其他信息。基本的反馈循环是使用浏览器识别我们要解析的内容,然后在终端中测试解析代码。

  起始网址

  如果您查看上面的链接,您可能会注意到该 URL 收录我们的搜索查询。这是在 HTTP GET 请求中传递参数的方式(此示例未使用标准化格式)。我们可以使用此信息以编程方式尝试不同的搜索查询。

  在 url 中,在字母 q 之后,我们看到了与位置对应的查询。字母 l 之后是位置。假设在我们的用例中,我们要搜索多个位置和位置。例如,医疗助理也称为患者护理助理。

  在scrapy中,我们可以使用我们蜘蛛的几个URL作为抓取的起点。我们可以向它传递与多个位置和位置相对应的 URL 以获得此行为。在这个例子中,我使用 product 函数生成位置和位置的每个组合,然后我将它传递给蜘蛛作为我们的起点。

  从 itertools 导入产品

  job_titles = [“医疗助理”、“病人护理技术员”、“病人护理助理”]

  状态 = [“MA”]

  城市 = [“波士顿”、“剑桥”、“萨默维尔”、“多*敏*感*词*”]

  网址 = []

  对于产品(job_titles,states,城市)中的(job_title,state,city):

  urls.append(f"{'-'.join(job_title.split())}-l-{city},-{state}-jobs.html")

  类确实蜘蛛(scrapy.Spider):

  名称 = "确实"

  allowed_domains = [""]

  start_urls = urls

  也许您已经注意到,在相邻城市中搜索相同的位置会产生重叠的结果。换句话说,在剑桥和波士顿搜索相同的标题将返回重复项。任何数据项目的主要挑战是重复数据删除。我们可以使用的一种策略是拥有像 redis 这样的应用程序缓存。我们的程序可以根据职位、公司名称、地点和发布日期组成的自然主键检查列表是否已解析。我们甚至可以在服务器生成的 DOM 中查找唯一 ID。为简单起见,一旦所有内容都保存到我们的对象存储中,我们将在最后进行重复数据删除。

  解析页面

  我将使用 Python 库 BeautifulSoup4 来解析 HTML,因为这是我最熟悉的库。默认情况下,scrapy 带有 CSS 选择器和 XPath 选择器,它们都是针对 DOM 编写查询的强大方法。在本教程中,您需要将 Beautiful Soup 导入我们的 shell,然后将 HTML 解析为一个 BeautifulSoup 对象。我喜欢 BeautifulSoup,因为 find API 非常简单。

  从 bs4 导入 BeautifulSoup

  汤 = BeautifulSoup(response.text, features="lxml")

  请注意,当他们重命名 CSS 类时,此解析代码将被破坏。如果您发现这些示例不起作用,请尝试修复它们以适应今天的 网站 结构和命名方法。

  首先,我们需要找到一种方法来解析给定页面上所有作业的列表。我们想找到一种方法来捕获每个列表的顶部节点。一旦我们有了每个列表的父节点,我们就可以迭代如何解析每个列表的属性。目前,每个列表都有一个顶级锚元素 (),class="tapItem"。我们可以使用 CSS 类来选择代表单个列表的所有这些节点。

  listings = soup.find_all("a", {"class": "tapItem"})

  在本教程中,我们将定位属性职位、雇主、地点和职位描述。前三个属性可以在搜索结果页面上找到,职位描述需要点击职位描述页面上的链接。从这个页面上可用的属性开始,我们可以使用 CSS 类在每个父节点中定位列表的不同属性。

  在列表中列出:

  job_title = listing.find("h2", {"class": "jobTitle"}).get_text().strip()

  summary = listing.find("div", {"class": "job-snippet"}).get_text().strip() # 去除换行符

  company = listing.find("span", {"class": "companyName"}).get_text().strip()

  location = listing.find("div", {"class": "companyLocation"}).get_text().strip()

  我通过在检查元素 devtools 中找到帖子然后在 iPython 中迭代代码来编写这段代码。在每种情况下,我发现通过 HTML 元素和 CSS 类进行选择就足以获得我需要的信息。

  现在我们需要检索位于单独页面上的职位描述。为此,我们将发送另一个 HTTP 请求,以使用我们在搜索结果页面上找到的链接检索收录职位描述的页面。我们通过将在锚标记的 href 中找到的相对路径与在我们的响应对象中找到的搜索结果页面的 URL 相结合来获得链接 url。然后我们会要求scrapy使用异步事件循环来调度请求。

  我们会将职位描述(jd)与我们在此页面上找到的信息结合起来,因此我们会将解析后的属性传递给回调函数,以便它们都可以存储在同一个项目中。Scrapy 需要使用 yield 语句,因为该函数是由异步调度器执行的。parse_jd 回调函数将返回一个表示职位发布的字典。

  发布 = {“job_title”:job_title,“summary”:摘要,“company”:公司,“location”:location}

  jd_page = listing.get("href")

  如果 jd_page 不是 None:

  yield response.follow(jd_page, callback=self.parse_jd, cb_kwargs=posting)

  现在剩下要做的就是解析工作描述并生成要采集的项目。幸运的是,职位描述有一个唯一的 ID。这是选择特定元素的最简单方法。我们想要保存职位描述的 URL,因为如果我们最终申请,我们将需要找到申请按钮的链接。

  def parse_jd(self, response, **posting):

  汤 = BeautifulSoup(response.text, features="lxml")

  jd = soup.find("div", {"id": "jobDescriptionText"}).get_text()

  url = response.url

  post.update({"job_description": jd, "url": url})

  收益过帐

  解析通常是编写蜘蛛程序最具挑战性和最耗时的阶段。网站 会随着时间的推移而变化,所以需要在断掉的时候修改代码。添加验证步骤以检查无字符串或空字符串然后引发错误会很有用。这样,当代码不再起作用时,您会收到通知。这应该只对关键路径信息进行,因为丢失的信息可能很常见。

  最后一步是告诉我们的爬虫去搜索结果的下一页。我们希望爬虫检索当前可用的每个帖子,而不仅仅是第一页上的结果。当下一页按钮不再可用时,我们就会知道我们已经完成了。

  next_page = soup.find("a", {"aria-label": "Next"}).get("href")

  如果 next_page 不是 None:

  next_page = response.urljoin(next_page)

  产生scrapy.Request(next_page,回调=self.parse)

  有了这些简单的指令集,我们现在有了一个相当强大的过程来提取所有重要的细节。跟随下一页上的链接的能力意味着爬虫将抓取所有可用的结果,而无需任何额外的编码。现在我们已经完成了蜘蛛的准备工作,我们可以继续研究结果。

  保存结果

  现在解析器已经写好了,我们可以开始使用一些scrapy特性了。我们可以选择使用 ItemPipline 将每个 Item 发送到文件对象存储或数据库。我们可以利用具有高写入吞吐量的高可用分布式数据库(例如DynamoDB、Cassandra)并在表运行时将项目插入表中。

  对于这个项目,我将使用内置提要选项从命令行创建一个摘录。我会选择 JSON 行,因为 JSON 编码器将正确转义换行符和引号,作为编组到 JSON 的过程的一部分。与 CSV 相比,这可以为您节省一些将来的麻烦,其中额外的换行符或引号可能会导致解析错误和头痛。当架构不是静态的并且每个项目可能收录的属性不同时,半结构化格式也很有用。

  有一种方法可以在配置文件中指定提要,但我将向您展示如何从命令行执行此操作。我们将创建一个 JSON Lines 文件,其中收录捕获到本地文件系统的所有数据。从那里我们可以开始与结果交互以提取价值。

  确实爬行抓取 -o jobs.jl

  这将需要一些时间来运行,具体取决于您配置的位置和位置的数量。所有 网站 都有某种形式的速率限制。可以通过 CDN 或负载均衡器/反向代理(如 Cloudflare)实现速率限制。速率限制可防止拒绝服务 (DoS) 攻击关闭 Web 服务器。Scrapy 将执行指数退避,直到得到 200 响应代码,这意味着它会在每次失败后等待更长时间,直到请求成功。

  分析结果

  现在我们有一个收录所有帖子的文件,我们可以开始分析。执行分析的一种方法是使用 Jupyter 笔记本。Jupyter Notebook 可用于探索性数据分析和非线性规划。当我们为发现和分析编码时,我们不知道最终状态是什么样的。我们在写代码的时候,需要改变事物的顺序,做出重大的改变,这就是为什么它被称为非线性规划。Jupyter 使这种编程风格更容易。

  Jupyter notebooks 通过使用单元格和 iPython 促进了这种类型的开发。通过使用 iPython 作为后端,它允许您在 REPL 环境中工作。REPL 允许您快速查看执行代码的输出并在创建对象后保留它们。第二部分是可以移动、剪切、复制和删除的单元格。单元格可以轻松更改执行顺序和更改对象的范围。我发现笔记本是我分析结果的好地方。

  综上所述

  下一步是聚合和规范化数据,分析它,然后创建某种用户界面来访问它。例如,您可以有一个网站,网站 显示所有已爬取的网站 根据自定义条件进行排序和过滤。您可以使用关键字检测来确定提供您最感兴趣的机会的列表的优先级。

  用scrapy写spider可以让你通过第一步,解析网页中的数据并保存。这是任何依赖网络爬行数据的数据管道中的第一个组件。一旦您捕获了数据,您就可以开始为您希望的任何应用程序从中提取价值。

  您可以从本教程下载收录所有代码的 python 文件。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线