python爬取两个网站_【Python数据科学实战系列】之Web信息爬取 | 详解 + Reddit等2个案例实践...

本文通过案例分析介绍如何通过Python中的Scrapy库进行网页数据爬取,内含代码分析,建议边阅读边实践,目录如下:

1. Scrapy简介2. 编写第一个网页爬取代码 2.1 安装Scrapy库 2.2 使用Scrapy Shell 进行快速试验 2.3 编写自定义Spider类3. 案例实践 3.1 Scrapy Shell调试代码 3.2 创建Spider类

e9fca151d80f45e38f7fd6df7ec6052c.gif

1. Scrapy 简介

Scrapy是一个用于大规模网络数据爬取的Python框架。它提供了一系列工具用于高效地爬取网站数据,并且可以根据需要进行数据处理,并保存为结构化信息。

由于互联网的多样性,并没有“一刀切”的方法爬取网站数据,因此许多时候都采取临时的方法。当为一个小型任务编写代码时,会创建一个数据爬取的框架,Scrapy就是这样的框架。

4bdcec4f71d94739a9e20ad3748cfec0.jpg

2. 编写第一个网页爬取代码

以下将逐步分析如何应用Scrapy编写一个网页爬取代码。

2.1 安装Scrapy库

Scrapy库支持Python2.0和3.0,建议使用Anaconda进行安装,也可以直接pip安装。

若使用Anaconda进行安装,如下:

conda install -c conda-forge scrapy

也可直接使用pip命令安装,如下:

pip install scrapy

注:本文在Python3.0环境中使用Scrapy

2.2 使用Scrapy Shell 进行快速试验

2017年夏,美剧《权力的游戏》第7季播放,在Reddit上形成了话题专区。以下将使用Scrapy Shell对关于权游的讨论话题、评论数量、相关用户等数据进行爬取。

权游话题讨论专区网址为:https://www.reddit.com/r/gameofthrones/ ,这也是用于爬取的URL。

注 :Reddit是一个娱乐、社交及新闻网站,注册用户可以将文字或链接在网站上发布,使它基本上成为了一个电子布告栏系统。注册用户可以对这些帖子进行投票,结果将被用来进行排名和决定它在首页或子页的位置。网站上的内容分类被称为“subreddit”。(来自维基百科)

关于Scrapy 终端(Scrapy Shell)

Scrapy终端是一个交互终端,供您在未启动spider的情况下尝试及调试您的爬取代码。 该终端是用来测试XPath或CSS表达式,查看他们的工作方式及从爬取的网页中提取的数据。 在编写您的spider时,该终端提供了交互性测试您的表达式代码的功能,免去了每次修改后运行spider的麻烦。(来自Scrapy 0.24.6 文档)

在cmd中启动Scrapy Shell:

scrapy shell

爬取权游话题网页:

fetch('https://www.reddit.com/r/gameofthrones/')

333b6d8645c743db88373c169ec968c5.jpg

当使用Scrapy进行爬取时,会返回一个response对象,里面包含了下载的信息,以下查看下载的内容:

view(response)

6cfc1ac749b34a6e85dbce21657d7e84.jpg

同时会打开已下载的网页:

02731b918abd4688b8cdc3ee2d268622.jpeg

以下查看下载网页的原始内容:

print(response.text)

cc5578f002c44d5e847069bbcd9fe35d.jpg

显示的内容非常多,以下为需要从中提取的内容:

每篇文章的标题

获得的投票数量

获得的评论数量

文章发布的时间

2.2.1 提取文章标题

Scrapy基于css采集器提供了多种从HTML源码中提取信息,比如class、id等。首先需要分析文章标题对应的css采集器,在网页上右键打开“检查”:

44ee2d70a8aa454a929f29359d4035a0.jpeg

0eac8319ce3544b8ba68fd437e09cbcc.jpeg

这会打开浏览器的开发者工具,从中找到title,位于

标签中,以此提取出response对象中的标题信息:

response.css(".title::text").extract()

f03602e4b4c545fb924e73615d047ff9.jpg

此处,response.css()方法基于css采集器传递给它的内容进行抽取。由于是css,title前需要加.。并且,::text告诉scraper只提取匹配元素中的text内容,这样做是因为scraper直接以HTML源代码的形式返回匹配的元素内容,比如:

dda3366385b843b8b7e12a22e8d08b0b.jpg

2.2.2 提取投票数量

fcea474a127640b58995d8b8f57e4128.jpg

此处,可以发现有三个得分信息,进一步查看网页内容,可以发现score unvoted对应的是投票数量。

当超过两个采集器用来定义一个元素时,它们都需要用来提取内容,而且都是css类,所以都需要使用.。以下尝试提取投票数量:

response.css(".score.unvoted").extract_first()

ba2ebff851b84dc489edb8ff8f6f11de.jpg

15ebf035dc7f41f3a0ee2364b6ba11f1.jpeg

对比网页信息,可以看出提取的投票数量是正确的,进一步需要使用::text只提取其中的数量,而不是整个vote元素。

response.css(".score.unvoted::text").extract()

c8a4eeee9a144da0b0792b823e627399.jpg

2.2.3 提取评论数量

与以上两次提取类似,提取评论数量:

response.css(".comments::text").extract()

8186536d3cc74ba49ed20cb77c88b24e.jpg

2.2.4 提取文章发布时间

按照以上逻辑提取文章发布时间:

response.css("time::text").extract()

注:此处time不是css类,不需要加.

4fc9cbaf4227482aa506235f12300d18.jpg

可以发现提取的内容为文章发布的相对时间,再次查看HTML源代码:

d04ba7b8c17a48c199643b8cf010216c.jpg

可以发现time中title属性中包括具体的日期和时间,因此使用.attr()提取获取匹配元素中指定属性的值:

response.css("time::attr(title)").extract()

e413bb20cc6b43099f0e1eae978ad9b9.jpg

2.3 编写自定义Spider类

Spider类时用于爬取网站内容的程序。由于网站设计的多样性,在大规模爬取数据时,需要为不同的网站编写自定义的Spider类,同时需要编写代码将爬取的内容转化为结构化格式,比如csv、json、excel等,这些都包含在Scrapy的内置功能中。

2.3.1 创建Scrapy项目

现在需要退出Scrapy Shell,再创建一个新的Scrapy项目:

scrapy startproject firstone

f0afd820112f4db99f48985882212804.jpg

以上创建了firstone文件夹,可以查看文件夹结构:

tree firstone /F

2477189740244701908ee4bf3e223d8d.jpg

此处,最重要的两个文件是:

settings.py——包含了项目的设置信息,可以进行一系列操作

spider/——该文件夹存储所有的自定义Spider类,每次运行一个Spider类,Scrapy会自动在此文件夹中查找并运行

2.3.2 创建Spider类

下面需要进入firstone文件夹,并创建一个spider类:redditbt

scrapy genspider redditbot www.reddit.com/r/gameofthrones/

8d3736844d934197bb2e785418ed6ca9.jpg

以上,在spider/文件夹中创建了redditbot.py文件,其内部包含了一个基本的模板:

268c14157b504d0080e00b545bd47e14.jpg

此处,关于以上模板中的内容:

name:Spider类的名字

allowed_domains:允许此Spider类爬取的网页地址,不属于此域名的URL无法爬取

parse(self,response):当成功爬取到一个URL时,会调用此函数,而且这里的response对象和前面提到的一致

每次爬取成功之后,都会调用parse()函数,这里就是编写提取逻辑的地方。现在添加之前试验过的提取逻辑,包括提取标题、投票数量、评论数量等。

def parse(self, response): # 使用css采集器提取内容 titles = response.css('.title.may-blank::text').extract() votes = response.css('.score.unvoted::text').extract() times = response.css('time::attr(title)').extract() comments = response.css('.comments::text').extract() # 将提取的内容按行排序 for item in zip(titles, votes, times, comments): # 创建字典存储爬取的信息 scraped_info = { 'title': item[0], 'vote': item[1], 'created_at': item[2], 'comments': item[3], } # 将爬取的信息传递给Scrapy yield scraped_info

此处,yield scraped_info将爬取的信息传递给Scrapy,后者将依次处理信息并存储。

保存redditbot.py文件,打开cmd,进入firstone文件夹,运行这个Spider类:

scrapy crawl redditbot

8f7bf80e493c4a4ba49aee1728251082.jpg

以上输出信息显示所有数据已经下载,并且存放在字典中。

2.3.3 将爬取的数据保存为csv格式

Scrapy可以将爬取的内容导出为csv、json等多种格式,现在打开settins.py文件,并且添加以下信息:

# 导出为csv文件FEED_FORMAT = "csv"FEED_URI = "reddit.csv"

0cd2e2939cef43a186761a657c2ad909.jpg

关于以上信息:

FEED_FORMAT:定义输出文件的格式,目前支持的格式有csv、json、json lines、xml

FEED_URI:输出文件的路径

再次运行这个Spider类:

scrapy crawl redditbot

这会在firstone文件夹中输出reddit.csv文件,内容如下:

0fd21301266e402db2100da9a6173eca.jpg

现在已经成功地创建了一个系统,可以爬取网页内容,从中提取目标信息,并且保存为结构化格式。下面将进行另外一个案例实践。

ed9e54073a6645d188f4c19d9902ffd0.jpg

3. 案例实践

64eb660c08374b48a3c5f8dff62e8f5c.jpeg

Techcrunch关于技术产品的博客网站,并且提供了自己的RSS源码: https://techcrunch.com/feed/。Scrapy的一大特点就是能够轻松处理XML数据,下面就要从Techcrunch的RSS源码中爬取信息。

查看Techcrunch的RSS源码,下面是需要提取的信息:

cefce8f011fa4b16b2889587ad44ffea.jpeg

从以上页面可以看出:

每篇文章的信息显示在标签中

文章标题保存在

标签中

文章链接保存在标签中

发布日期保存在中

作者姓名保存在中

关于XPath和XML

XPath是用来定义XML文档的语法,可以用来遍历一个XML文档,并且遵循层次结构。

3.1 Scrapy Shell调试代码

和第2部分类似,首先在Scrapy Shell中调试代码。

爬取网页:

fetch('https://techcrunch.com/feed/')

7c2522f312954792bf92ab65cedd89af.jpg

3.1.1 提取文章标题、链接及发布日期信息

和response.css()方法类似,response.xpath()方法用于处理XPath,现在提取文章标题信息:

response.xpath("//item/title").extract_first()

aec94e81bd9d4b7fa13684c0f15676be.jpg

输出结果较多,进一步需要提取出标题部分:

response.xpath("//item/title/text()").extract_first()

a9c8c6eb4a984e5c97da6bd14f708163.jpg

此处text()相当于CSS采集器中::text,关于XPath//item/title/text()是指,查找item元素,从text子元素中提取text部分。

类似的,对于链接以及发布日期的XPath提取:

Link-//item/link/text()

Date of publishing-//item/pubDate/text()

3.1.2 提取作者姓名信息

提取作者信息如下:

response.xpath("//item/creator/text()").extract_first()

并没有得到结果,因此查看标签:

ec2d82bb359f4dd68442f8c5abb143fb.jpeg

标签含有dc:,因此使用XPath不能提取,而且姓名部分含有![CDATA[]]相关文本。这些是XML的命名空间,需要先删除这些命名空间再提取内容:

response.selector.remove_namespaces()

再次提取作者姓名信息:

response.xpath("//item/creator/text()").extract_first()

fc501a83cc694e97a0f9fe7ca538bb2e.jpg

3.2 创建Spider类

代码调试完成后,从Scrapy Shell退出,进入firstone文件夹,创建一个新的Spider类:

Scrapy genspider techcrunch techcrunch.com/feed/

1737652263254a2a9a35b4379d9b8179.jpg

接着,将调试过的代码添加到techcrunch.py文件中,完整的代码如下:

import scrapyclass TechcrunchSpider(scrapy.Spider): name = 'techcrunch' allowed_domains = ['techcrunch.com/feed/'] start_urls = ['http://techcrunch.com/feed//'] # 设置输出csv文件的路径 custom_settings = { 'FEED_URI': 'tmp/techcrunch.csv' } def parse(self, response): # 删除XML命名空间 response.selector.remove_namespaces() # 提取文章信息 titles = response.xpath('//item/title/text()').extract() authors = response.xpath('//item/creator/text()').extract() dates = response.xpath('//item/pubDate/text()').extract() links = response.xpath('//item/link/text()').extract() for item in zip(titles, authors, dates, links): scraped_info = { 'title': item[0], 'author': item[1], 'publish_date': item[2], 'link': item[3] } yield scraped_info

注 :以上代码中添加了输出csv文件的路径,如果不添加这部分代码,由于前面在settings.py中设置了输出路径,爬取的数据将被保存到techcrunch.csv文件中。

保存techcrunch.py文件,打开cmd,进入firstone文件夹,运行这个Spider类:

scrapy crawl techcrunch

得到csv文件内容如下:

bf515d89e79c48f9a95f05ba9b5180c1.jpg

本文由朝乐门、刘岩翻译,整理并实践后总结,源自Mohd Sanad Zaki Rizvi 在https://www.analyticsvidhya.com/上的文章。

【原文地址】https://www.analyticsvidhya.com/blog/2017/07/web-scraping-in-python-using-scrapy/

【源代码】https://github.com/LemenChao/web-scraping-magic-with-scrapy-and-python

《数据科学理论与实践》

作者:朝乐门

定价:59元

ISBN:9787302480549

图文来自网络、如涉及版权问题,请联系我们以便处理。文章内容纯属作者个人观点,不代表本网观点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值