scrapy分页抓取网页(牛津小马哥web前端工程师陈小妹妹(之前)(图) )
优采云 发布时间: 2022-04-19 16:44scrapy分页抓取网页(牛津小马哥web前端工程师陈小妹妹(之前)(图)
)
原创:陈晓梅,Oxford Pony Brothers Web 前端工程师。
在本文中,我将编写一个网络爬虫,从 OLX 的电子和电器项目中抓取数据。但在我进入代码之前,这里先简要介绍一下 Scrapy 本身。
什么是刮痧?
Scrapy(发音为 Scrapy)是一个用 Python 编写的开源网络爬虫框架。最初是为网页抓取而设计的。目前由 Scrapinghub 维护。
>>>>
创建一个项目。
Scrapy的一个设计思路是一个项目可以收录多个爬虫。这种设计很有用,尤其是在为站点或子域的不同部分编写多个机器人时。所以首先创建项目:
Adnans-MBP:ScrapyCrawlers AdnanAhmad$ scrapy startproject olxNew
Scrapy project 'olx', using template directory '//anaconda/lib/python2.7/site-packages/scrapy/templates/project', created in:
/Development/PetProjects/ScrapyCrawlers/olx
You can start your first spider with:
cd olx
scrapy genspider example example.com
>>>>
创建爬虫
我运行了命令 scrapy startproject olx,它将创建一个名为 olx 的项目。接下来,进入新创建的文件夹,执行命令生成第一个爬虫,并带有要爬取的站点的名称和域:
Adnans-MBP:ScrapyCrawlers AdnanAhmad$ cd olx/
Adnans-MBP:olx AdnanAhmad$ scrapy genspider electronics www.olx.com.pk
Created spider 'electronics' using template 'basic' in module:
olx.spiders.electronics
下面是 OLX 的“电子”文件部分,最终的项目结构将类似于以下示例:
如您所见,这个新创建的爬虫有一个单独的文件夹。您可以将多个爬虫添加到一个项目中。让我们打开爬虫文件electronics.py。当您打开它时,您将看到以下内容:
# -*- coding: utf-8 -*-
import scrapy
class ElectronicsSpider(scrapy.Spider):
name = "electronics"
allowed_domains = ["www.olx.com.pk"]
start_urls = ['http://www.olx.com.pk/']
def parse(self, response):
pass
如您所见,ElectronicsSpider 是 scrapy.Spider 的子类。name 属性其实就是蜘蛛的名字,在spider中指定。allowed_domains 属性告诉我们这个爬虫可以访问哪些域,start_urls 位置是需要首先访问初始 URL 的位置。
parse 顾名思义,这个方法会解析被访问页面的内容。由于我想写一个爬虫到多个页面,我会做一些改变。
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
class ElectronicsSpider(CrawlSpider):
name = "electronics"
allowed_domains = ["www.olx.com.pk"]
start_urls = [
'https://www.olx.com.pk/computers-accessories/',
'https://www.olx.com.pk/tv-video-audio/',
'https://www.olx.com.pk/games-entertainment/'
]
rules = (
Rule(LinkExtractor(allow=(), restrict_css=('.pageNextPrev',)),
callback="parse_item",
follow=True),)
def parse_item(self, response):
print('Processing..' + response.url)
为了让爬虫导航到多个页面,我从 scrapy.Spider 子类化为 CrawlSpider。这个类可以更容易地抓取 网站 的许多页面。您可以对生成的代码执行类似的操作,但您需要小心递归以导航下一页。
下一步是设置规则变量。在这里可以设置浏览网站的规则。在 LinkExtractor 中设置一些导航限制。这里我使用restrict_css参数来设置NEXT页面的类。如果您转到此页面并检查元素,您可以找到以下内容:
pageNextPrev 是用于获取下一页链接的类。call_back 参数告诉使用哪种方法来访问页面元素。
请记住,您需要将方法的名称从 parse() 更改为 parse_item() 或其他名称,以避免覆盖基类,否则即使您设置 follow=True ,您的规则也将不起作用。
到现在为止还挺好; 让我们测试一下到目前为止我们制作的爬虫。转到终端,在项目目录中输入:
scrapy crawl electronics
第三个参数其实是蜘蛛的名字,ElectronicsSpiders,之前在类名属性中设置的。在终端中,您会发现许多有助于调试的有用信息。如果不想看到调试信息,可以禁用调试器。此命令类似于 --nologswitch。
scrapy crawl --nolog electronics
如果现在运行,它将显示以下内容:
Adnans-MBP:olx AdnanAhmad$ scrapy crawl --nolog electronics
Processing..https://www.olx.com.pk/computers-accessories/?page=2
Processing..https://www.olx.com.pk/tv-video-audio/?page=2
Processing..https://www.olx.com.pk/games-entertainment/?page=2
Processing..https://www.olx.com.pk/computers-accessories/
Processing..https://www.olx.com.pk/tv-video-audio/
Processing..https://www.olx.com.pk/games-entertainment/
Processing..https://www.olx.com.pk/computers-accessories/?page=3
Processing..https://www.olx.com.pk/tv-video-audio/?page=3
Processing..https://www.olx.com.pk/games-entertainment/?page=3
Processing..https://www.olx.com.pk/computers-accessories/?page=4
Processing..https://www.olx.com.pk/tv-video-audio/?page=4
Processing..https://www.olx.com.pk/games-entertainment/?page=4
Processing..https://www.olx.com.pk/computers-accessories/?page=5
Processing..https://www.olx.com.pk/tv-video-audio/?page=5
Processing..https://www.olx.com.pk/games-entertainment/?page=5
Processing..https://www.olx.com.pk/computers-accessories/?page=6
Processing..https://www.olx.com.pk/tv-video-audio/?page=6
Processing..https://www.olx.com.pk/games-entertainment/?page=6
Processing..https://www.olx.com.pk/computers-accessories/?page=7
Processing..https://www.olx.com.pk/tv-video-audio/?page=7
Processing..https://www.olx.com.pk/games-entertainment/?page=7
由于我设置了follow=True,爬虫会检查NEXT页面的规则,并继续导航,直到到达不满足规则的页面,通常是列表的最后一页。
Scrapy 解除了编写爬虫的所有任务,让我可以专注于主要逻辑,通过编写爬虫来提取信息。
现在,我将继续编写代码以从列表页面获取单个项目链接。我将在 parse_item 方法中对其进行修改。
item_links = response.css('.large > .detailsLink::attr(href)').extract()
for a in item_links:
yield scrapy.Request(a, callback=self.parse_detail_page)
在这里,我使用 .css 响应方法获取链接。您也可以使用 xpath,这取决于您。在这种情况下,它非常简单:
锚链接有一个类 detailsLink。如果您只使用 response.css('.detailsLink'),由于 img 和 h3 标签中的重复链接,它将为单个条目选择重复链接。我还提到了用于唯一链接的大型父类。我之前提取的 href 部分 ::attr(href) 是链接本身。然后,我使用 extract() 方法。
使用此方法的原因是 .css 和 .xpath 返回 SelectorList 对象,而 extract() 有助于返回实际的 DOM 以供进一步处理。最后,我在 scrapy.Request 回调中收录了 yield 链接。我没有检查 Scrapy 的内部代码,但很可能他们使用的是 yield 而不是 A, return 因为你可以生产多个项目。由于爬虫需要同时处理多个链接,因此 yield 是这里的最佳选择。
parse_detail_page 顾名思义,这个方法会解析详情页中的个体信息。所以实际发生的是:
您将获得 parse_item 中的项目列表。
您将它们传递给回调方法以进行进一步处理。
由于它只是一个两层遍历,我可以借助两种方法到达最低层。如果要从OLX主页开始爬,这里要写三个方法:前两个获取子类及其条目,最后一个解析实际信息。知道了?
最后,我将解析实际信息,这些信息可以在与此类似的项目中找到。
解析此页面中的信息没有什么不同,但需要一些操作来存储解析的信息。我们需要为数据定义一个模型。这意味着我们需要告诉 Scrapy 我们想要存储哪些信息以供以后使用。让我们编辑之前由 Scrapy 生成的 item.py 文件。
import scrapy
class OlxItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
pass
OlxItem 我将设置所需字段以保存信息的类。我将为模型类定义三个字段。
class OlxItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
price = scrapy.Field()
url = scrapy.Field()
我将存储帖子的标题、价格和 URL 本身。
让我们回到爬虫类,修改parse_detail_page。
现在,一种方法是开始编写代码,通过运行整个爬虫来测试它,看看你是否走在正确的轨道上,但是 Scrapy 提供了另一个很棒的工具。
>>>>
废壳
Scrapy Shell 是一个命令行工具,允许您在不运行整个爬虫的情况下测试解析代码。与访问所有链接的爬虫不同,Scrapy Shell 保存单个页面的 DOM 以进行数据提取。就我而言,我做了以下事情:
Adnans-MBP:olx AdnanAhmad$ scrapy shell https://www.olx.com.pk/item/asus-eee-pc-atom-dual-core-4cpus-beautiful-laptops-fresh-stock-IDUVo6B.html#4001329891
现在我可以轻松地测试代码,而不必一次又一次地访问相同的 URL。我这样做是为了获得标题:
In [8]: response.css('h1::text').extract()[0].strip()
Out[8]: u"Asus Eee PC Atom Dual-Core 4CPU's Beautiful Laptops fresh Stock"
您可以在 response.css 中找到熟悉的内容。由于整个 DOM 都可用,因此您可以使用它。
我通过这样做得到价格:
In [11]: response.css('.pricelabel > strong::text').extract()[0]
Out[11]: u'Rs 10,500'
由于 response.url 返回的是当前访问的 URL,所以不需要做任何事情来获取 url。
现在已经检查了所有代码,是时候将其合并到 parse_detail_page 中了:
title = response.css('h1::text').extract()[0].strip()
price = response.css('.pricelabel > strong::text').extract()[0]
item = OlxItem()
item['title'] = title
item['price'] = price
item['url'] = response.url
yield item
解析所需信息后,OlxItem 将创建实例并设置属性。现在是时候运行爬虫并存储信息了,对命令进行了一些修改:
scrapy crawl electronics -o data.csv -t csv
我正在传递文件名和文件格式来保存数据。运行后,它将为您生成 CSV。很简单,不是吗?与您自己编写的爬虫不同,您必须编写自己的例程来保存数据。
可是等等!它并不止于此,您甚至可以获取 JSON 格式的数据。您所要做的就是使用 -t 开关传递 json。
Scrapy 为您提供了另一个功能。在实际情况下,传递一个固定的文件名没有任何意义。如何生成唯一的文件名?好吧,为此,您需要修改 settings.py 文件并添加以下两个条目:
FEED_URI = 'data/%(name)s/%(time)s.json'
FEED_FORMAT = 'json'
这里我给出文件的模式,%(name)% 是爬虫本身的名字和时间戳。你可以在这里了解更多。现在,当我运行 scrapy crawl --nolog electronics 或 scrapy crawl electronics 时,它会在 data 文件夹中生成一个 JSON 文件,如下所示:
[
{"url": "https://www.olx.com.pk/item/acer-ultra-slim-gaming-laptop-with-amd-fx-processor-3gb-dedicated-IDUQ1k9.html", "price": "Rs 42,000", "title": "Acer Ultra Slim Gaming Laptop with AMD FX Processor 3GB Dedicated"},
{"url": "https://www.olx.com.pk/item/saw-machine-IDUYww5.html", "price": "Rs 80,000", "title": "Saw Machine"},
{"url": "https://www.olx.com.pk/item/laptop-hp-probook-6570b-core-i-5-3rd-gen-IDUYejF.html", "price": "Rs 22,000", "title": "Laptop HP Probook 6570b Core i 5 3rd Gen"},
{"url": "https://www.olx.com.pk/item/zong-4g-could-mifi-anlock-all-sim-supported-IDUYedh.html", "price": "Rs 4,000", "title": "Zong 4g could mifi anlock all Sim supported"},
...
]