15个最受欢迎的Python开源框架

本文介绍如何使用Scrapy抓取StackOverflow的新问题标题和URL,并将数据存储到MongoDB中。涵盖Scrapy安装、XPath选择器使用及MongoDB集成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章将根据真实的兼职需求编写一个爬虫,用户想要一个Python程序从Stack Overflow抓取数据,获取新的问题(问题标题和URL)。抓取的数据应当存入MongoDB。值得注意的是,Stack Overflow已经提供了可用于读取同样数据的API。但是用户想要一个爬虫,那就给他一个爬虫。

像往常一样,在开始任何抓取工作前,一定要先查看该网站的使用/服务条款,要尊重 robots.txt 文件。抓取行为应该遵守道德,不要在很短时间内发起大量请求,从而导致网站遭受泛洪攻击。对待那些你要抓取的网站,要像对待自己的一样。

安装

我们需要Scrapy库(v0.24.4),以及用于在MongoDB中存储数据的PyMongo库(v2.7.2)。同样需要安装MongoDB。

Scrapy

如果使用OSX或某种Linux,使用pip安装Scrapy(激活命令行):

1
$ pip install Scrapy

如果使用Windows的机器,你需要手动安装一堆依赖库(木羊吐槽:Win下也是有pip的po主你不要黑她,经测可以用上面命令直接安装成功)。请参考官方文档详细说明以及我创建的Youtube视频。

一旦Scrapy安装完毕,可在Python命令行中使用这个命令验证:

1
2
>>> import scrapy
>>>

如果没有出错,安装就完成了。

PyMongo

下一步,使用pip安装PyMongo:

1
$ pip install pymongo

现在可以开始构建爬虫了。

Scrapy工程

先创建一个新的Scrapy工程:

1
$ scrapy startproject stack

这条命令创建了许多文件和文件夹,其中包含一套有助于你快速开始的基本模板:

1
2
3
4
5
6
7
8
├── scrapy.cfg
└── stack
     ├── __init__.py
     ├── items.py
     ├── pipelines.py
     ├── settings.py
     └── spiders
         └── __init__.py

提取数据

items.py文件用于定义存储“容器”,用来存储将要抓取的数据。

StackItem()类继承自Item (文档),主要包含一些Scrapy已经为我们创建好的预定义对象:

1
2
3
4
5
6
import scrapy
 
class StackItem(scrapy.Item):
     # define the fields for your item here like:
     # name = scrapy.Field()
     pass

添加一些想要收集的项。用户想要每条问题的标题和URL。那么,照这样更新items.py:

1
2
3
4
5
from scrapy.item import Item, Field
 
class StackItem(Item):
     title = Field()
     url = Field()

创建蜘蛛

在“spiders”目录下建立一个名为stack_spider.py的文件。这里是见证奇迹发生的地方—-比如在这里告诉Scrapy怎么去找到我们想要的指定数据。正如你想的那样,对于每一个独立的网页,stack_spider.py都是不同的。

我们从定义一个类开始,这个类继承Scrapy的Spider,并添加一些必须的属性:

1
2
3
4
5
6
7
8
9
from scrapy import Spider
 
 
class StackSpider(Spider):
     name = "stack"
     allowed_domains = [ "stackoverflow.com" ]
     start_urls = [
         "http://stackoverflow.com/questions?pagesize=50&sort=newest" ,
     ]

最初一些变量的含义很容易理解(文档):

  • 定义蜘蛛的名字。
  • allowed_domains 包含构成许可域的基础URL,供蜘蛛去爬。
  • start_urls 是一个URL列表,蜘蛛从这里开始爬。蜘蛛从start_urls中的URL下载数据,所有后续的URL将从这些数据中获取。

XPath选择器

接下来,Scrapy使用XPath选择器在一个网站上提取数据。也就是说,我们可以通过一个给定的XPath选择HTML数据的特定部分。正如Scrapy所称,“XPath是一种选择XML节点的语言,也可以用于HTML。”

使用Chrome的开发者工具,可以很容易找到一个特定的Xpath。简单地检查一个特定的HTML元素,复制XPath,然后修改(如有需要)。

开发者工具同时为用户提供在JavaScript控制台测试XPath选择器的功能,使用$x,如$x("//img"):

继续,通过定义的XPath告诉Scrapy去哪里寻找信息。在Chrom中导航至Stack Overflow网址,寻找XPath选择器。

右键点击第一条问题,选择“插入元素”:

现在从<div class="summary">, //*[@id="question-summary-27624141"]/div[2]中抓取XPath,然后在JavaScript控制台测试它:

也许你会说,这只选择了一条问题。现在需要改变XPath去抓取所有的问题。有什么想法?很简单://div[@class="summary"]/h3

什么意思呢?本质上,这条XPath是说:抓取<div>的子树中所有这一类<h3>元素的总集。在JavaScript控制台中测试XPath。

请注意我们不会使用Chrome开发者工具的实际输出。在大多数案例中,这些输出仅仅是一个参考,便于直接找到能用的XPath。

现在更新stack_spider.py脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
from scrapy import Spider
from scrapy.selector import Selector
 
 
class StackSpider(Spider):
     name = "stack"
     allowed_domains = [ "stackoverflow.com" ]
     start_urls = [
         "http://stackoverflow.com/questions?pagesize=50&sort=newest" ,
     ]
 
     def parse( self , response):
         questions = Selector(response).xpath( '//div[@class="summary"]/h3' )

提取数据

我们仍然需要解析和抓取想要的数据,它符合<div class="summary"&gt<h3&gt。继续,像这样更新stack_spider.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from scrapy import Spider
from scrapy.selector import Selector
 
from stack.items import StackItem
 
 
class StackSpider(Spider):
     name = "stack"
     allowed_domains = [ "stackoverflow.com" ]
     start_urls = [
         "http://stackoverflow.com/questions?pagesize=50&sort=newest" ,
     ]
 
     def parse( self , response):
         questions = Selector(response).xpath( '//div[@class="summary"]/h3' )
 
         for question in questions:
             item = StackItem()
             item[ 'title' ] = question.xpath(
                 'a[@class="question-hyperlink"]/text()' ).extract()[ 0 ]
             item[ 'url' ] = question.xpath(
                 'a[@class="question-hyperlink"]/@href' ).extract()[ 0 ]
             yield item

我们将遍历问题,从抓取的数据中分配标题和URL的值。一定要利用Chrome开发者工具的JavaScript控制台测试XPath的选择器,例如$x('//div[@class="summary"]/h3/a[@class="question-hyperlink"]/text()')$x('//div[@class="summary"]/h3/a[@class="question-hyperlink"]/@href')

测试

准备好第一次测试了吗?只要简单地在“stack”目录中运行下面命令:

1
$ scrapy crawl stack

随着Scrapy堆栈跟踪,你应该看到50条问题的标题和URL输出。你可以用下面这条小命令输出一个JSON文件:

1
$ scrapy crawl stack - o items.json - t json

我们已经基于要寻找的数据实现了爬虫。现在需要将抓取的数据存入MongoDB。

在MongoDB中存储数据

每当有一项返回,我们想验证数据,然后添加进一个Mongo集合。

第一步是创建一个我们计划用来保存所有抓取数据的数据库。打开settings.py,指定管道然后加入数据库设置:

1
2
3
4
5
6
ITEM_PIPELINES = ['stack.pipelines.MongoDBPipeline', ]
 
MONGODB_SERVER = "localhost"
MONGODB_PORT = 27017
MONGODB_DB = "stackoverflow"
MONGODB_COLLECTION = "questions"

管道管理

我们建立了爬虫去抓取和解析HTML,而且已经设置了数据库配置。现在要在pipelines.py中通过一个管道连接两个部分。

连接数据库

首先,让我们定义一个函数去连接数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pymongo
 
from scrapy.conf import settings
 
 
class MongoDBPipeline( object ):
 
     def __init__( self ):
         connection = pymongo.Connection(
             settings[ 'MONGODB_SERVER' ],
             settings[ 'MONGODB_PORT' ]
         )
         db = connection[settings[ 'MONGODB_DB' ]]
         self .collection = db[settings[ 'MONGODB_COLLECTION' ]]

这里,我们创建一个类,MongoDBPipeline(),我们有一个构造函数初始化类,它定义Mongo的设置然后连接数据库。

处理数据

下一步,我们需要定义一个函数去处理被解析的数据:

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
import pymongo
 
from scrapy.conf import settings
from scrapy.exceptions import DropItem
from scrapy import log
 
 
class MongoDBPipeline( object ):
 
     def __init__( self ):
         connection = pymongo.Connection(
             settings[ 'MONGODB_SERVER' ],
             settings[ 'MONGODB_PORT' ]
         )
         db = connection[settings[ 'MONGODB_DB' ]]
         self .collection = db[settings[ 'MONGODB_COLLECTION' ]]
 
     def process_item( self , item, spider):
         valid = True
         for data in item:
             if not data:
                 valid = False
                 raise DropItem( "Missing {0}!" . format (data))
         if valid:
             self .collection.insert( dict (item))
             log.msg( "Question added to MongoDB database!" ,
                     level = log.DEBUG, spider = spider)
         return item

我们建立一个数据库连接,解包数据,然后将它存入数据库。现在再测试一次!

测试

再次,在“stack”目录下运行下面命令:

1
$ scrapy crawl stack

万岁!我们已经成功将我们爬下了的数据存入数据库:

总结

这是一个用Scrapy爬取网页的简单示例。真实兼职工作需要能跟踪分页链接的脚本,用CrawlSpider(文档)抓取每一个页面,非常容易实现。自己动手实现下,在下面Github仓库链接中写一个评论,快速查看代码。需要帮助?从这个脚本开始,它已经很接近完成了。然后查看第二部分,它包含完整的解决方案。

你可以从Github repo中下载完整的代码。如果有问题请跟贴评论。谢谢阅读!

新年快乐

关于作者: 木羊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值