查看原文
其他

使用Scrapy自建数据集

Michael Galarnyk 论智 2022-08-24
来源:Medium编译:weakish

编者按:斯克里普斯研究所数据科学家Michael Galarnyk介绍了如何使用Scrapy爬取网站数据。

我刚开始在业界工作时,首先意识到的一件事情是,有时候需要自己收集、整理、清洗数据。在这篇教程中,我们将从一个众筹网站FundRazr收集数据。和许多网站一样,这个网站有自己的结构、形式,还有众多有用的数据,但却没有一个结构化的API,所以获取数据并不容易。在这篇教程中,我们将爬取网站数据,将其整理为有序的形式,以创建我们自己的数据集。

我们将使用Scrapy,一个构建网页爬虫的框架。Scrapy可以帮助我们创建和维护网页爬虫。它让我们可以专注于使用CSS选择器和XPath表达式提取数据,更少操心爬虫的内部工作机制。这篇教程比Scrapy官方教程要深入一点,希望你在读完这篇教程后,碰到需要抓取有一定难度的数据的情况时,也能自行完成。好了,让我们开始吧。

预备

如果你已经安装了anaconda和google chrome(或Firefox),可以跳过这一节。

  1. 安装Anaconda。你可以从官网下载anaconda自行安装,也可以参考我之前写的anaconda安装教程(Mac、Windows、Ubuntu、环境管理)。

  2. 安装Scrapy。其实Anaconda已经自带了Scrapy,不过如果遇到问题,你也可以自行安装:

    1. conda install -c conda-forge scrapy

  3. 确保你安装了chrome或firefox. 在这篇教程中,我将使用chrome.

创建新Scrapy项目

  1. startproject命令可以创建新项目:

    该命令会创建一个fundrazr目录:

    1. fundrazr/

    2.    scrapy.cfg      # 部署配置文件

    3.    fundrazr/       # 项目的Python模块

    4.        __init__.py

    5.        items.py    # 项目item定义

    6.        pipelines.py # 项目pipeline文件

    7.        settings.py # 项目设置文件

    8.        spiders/    # 爬虫目录

    9.            __init__.py

    10. scrapy startproject fundrazr


使用chrome(或firefox)的开发者工具查找初始url

在爬虫框架中,start_urls是爬虫开始抓取的url列表。我们将通过start_urls列表中的每个元素得到单个项目页面的链接。

下图显示,选择的类别不同,初始url也不一样。黑框高亮的部分是待抓取的类别。

在本教程中,start_urls列表中的第一项是:

  1. https://fundrazr.com/find?category=Health

接下来,我们将看看如何访问下一页,并将相应的url加入start_urls

第二个url是:

  1. https://fundrazr.com/find?category=Health&page=2

下面是创建start_urls列表的代码。其中,npages指定翻页的页数。

  1. start_urls = ["https://fundrazr.com/find?category=Health"]

  2. npages = 2

  3. for i in range(2, npages + 2 ):

  4.    start_urls.append("https://fundrazr.com/find?category=Health&page="+str(i)+"")


使用Srapy shell查找单个项目页面

使用Scrapy shell是学习如何基于Scrapy提取数据的最好方法。我们将使用XPaths,XPaths可以用来选择HTML文档中的元素。

我们首先需要尝试获取单个项目页面链接的XPath。我们将利用浏览器的检查元素。

我们将使用XPath提取下图中红框内的部分。

我们首先启动Scrapy shell:

  1. scrapy shell 'https://fundrazr.com/find?category=Health'

在Scrapy shell中输入以下代码:

  1. response.xpath("//h2[contains(@class, 'title headline-font')]/a[contains(@class, 'campaign-link')]//@href").extract()

使用exit()退出Scrapy shell.

单个项目页面

之前我们介绍了如何提取单个项目页面链接。现在我们将介绍如何提取单个项目页面上的信息。

首先我们前往将要抓取的单个项目页面(链接见下)。

使用上一节提到的方法,检查页面的标题。

现在我们将再次使用Scrapy shell,只不过这次是在单个项目页面启动。

  1. scrapy shell 'https://fundrazr.com/savemyarm'

提取标题的代码是:

  1. response.xpath("//div[contains(@id, 'campaign-title')]/descendant::text()").extract()[0]

页面其他部分同理:

  1. # 筹款总额

  2. response.xpath("//span[contains(@class,'stat')]/span[contains(@class, 'amount-raised')]/descendant::text()").extract()

  3. # 筹款目标

  4. response.xpath("//div[contains(@class, 'stats-primary with-goal')]//span[contains(@class, 'stats-label hidden-phone')]/text()").extract()

  5. # 币种

  6. response.xpath("//div[contains(@class, 'stats-primary with-goal')]/@title").extract()

  7. # 截止日期

  8. response.xpath("//div[contains(@id, 'campaign-stats')]//span[contains(@class,'stats-label hidden-phone')]/span[@class='nowrap']/text()").extract()

  9. # 参与数

  10. response.xpath("//div[contains(@class, 'stats-secondary with-goal')]//span[contains(@class, 'donation-count stat')]/text()").extract()

  11. # 故事

  12. response.xpath("//div[contains(@id, 'full-story')]/descendant::text()").extract()

  13. # url

  14. response.xpath("//meta[@property='og:url']/@content").extract()


Items

网页抓取的主要目标是从无结构的来源提取出结构信息。Scrapy爬虫以Python字典的形式返回提取数据。尽管Python字典既方便又熟悉,但仍然不够结构化:字段名容易出现拼写错误,返回不一致的信息,特别是在有多个爬虫的大型项目中。因此,我们定义Item类来(在输出数据之前)存储数据。

  1. import scrapy

  2. class FundrazrItem(scrapy.Item):

  3.    campaignTitle = scrapy.Field()

  4.    amountRaised = scrapy.Field()

  5.    goal = scrapy.Field()

  6.    currencyType = scrapy.Field()

  7.    endDate = scrapy.Field()

  8.    numberContributors = scrapy.Field()

  9.    story = scrapy.Field()

  10.    url = scrapy.Field()

将其保存在fundrazr/fundrazr目录下(覆盖原本的items.py文件)。

爬虫

我们定义爬虫类,供Scrapy使用,以抓取一个网站(或一组网站)的信息。

  1. # 继承scrapy.Spider类

  2. class Fundrazr(scrapy.Spider):

  3.    # 指定爬虫名称,运行爬虫时要要到

  4.    name = "my_scraper"

  5.    # 定义start_urls、npages

  6.    # 具体定义见前

  7.    def parse(self, response):

  8.        for href in response.xpath("//h2[contains(@class, 'title headline-font')]/a[contains(@class, 'campaign-link')]//@href"):

  9.            # 加上协议名称

  10.            url = "https:" + href.extract()

  11.            # 异步抓取

  12.            yield scrapy.Request(url, callback=self.parse_dir_contents)

  13.    # 回调函数定义

  14.    def parse_dir_cntents(self, response):

  15.        item = FundrazrItem()

  16.        # 下面依次定义item的各字段,

  17.        # 具体定义参见前面的XPath表达式

  18.        yield item

为了节约篇幅,以上代码仅仅呈现了爬虫的大致结构,省略了导入依赖的语句以及前几节已经涉及的具体代码。完整代码可以从我的GitHub仓库获取:mGalarnyk/Python_Tutorials

爬虫代码保存在fundrazr/spiders目录下,文件命名为fundrazr_scrape.py

运行爬虫

fundrazr/fundrazr目录下输入:

  1. scrapy crawl my_scraper -o MonthDay_Year.csv

数据输出文件位于fundrazr/fundrazr目录下。

我们的数据

输出的数据应该类似下面的图片。由于网站不断地更新,因此具体的众筹项目会不同。另外,项目记录间可能会有空行,这是excel解析csv文件时会出现的现象。

我将npages2改到了450,并增加了download_delay = 2,抓取了约6000个项目,保存为MiniMorningScrape.csv文件。你可以从我的GitHu仓库直接下载这一文件:mGalarnyk/Python_Tutorials

结语

创建数据集可能需要大费周章,而在学习数据科学时却常常被忽略。教程中没有涉及清理数据,我将把这部分内容留给以后的博客文章。如果你有任何问题,请给我留言!

最后,我为这篇教程制作了一个时长约30分钟的配套视频,可以在YouTube上观看:https://youtu.be/O_j3OTXw2_E

如访问YouTube有困难,也可在论智公众号(ID: jqr_AI)后台留言scrapy,获取视频mp4及英文字幕下载地址。

原文地址:https://towardsdatascience.com/using-scrapy-to-build-your-own-dataset-64ea2d7d4673

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存