爬虫的基本工作原理 用Scrapy实现一个简单的爬虫

描述

数以万亿的网页通过链接构成了互联网,爬虫的工作就是从这数以万亿的网页中爬取需要的网页,从网页中采集内容并形成结构化的数据。

1、 爬虫的基本工作原理

爬虫是就是一个程序,这个程序的任务就是从给出的一组种子URL开始爬取网页,并通过网页间的链接爬取更多的网页,根据爬虫任务的需求,最终可能会爬取整个互联网的网页。

爬虫的工作机制如下图示:

爬虫

URL就是网页的网址,种子URL就是爬虫要首先爬取的网页网址,确定你的爬虫程序首先从哪些网页开始爬取。一组种子URL是指一个或多个的网页地址。

爬虫程序开始工作后,种子URL会先加入到待爬取网页的队列中,爬虫程序从队列按照先进先出的原则获取网页URL,爬虫程序开始爬取网页,爬虫会下载整个网页内容,然后提取网页内容,分析出网页内容包含的URL,并把新的URL加入到队列。

当队列为空时,爬虫停止工作,否则爬虫会继续从队列获取网页URL,爬取下一个网页。

Python爬虫基础代码如下:

# 导入队列模块
import queue as q
# 定义种子URL
seed_url = ["https://news.baidu.com/","https://money.163.com/"]
# 定义URL队列
url_queue = q.Queue()
# 定义添加种子到队列的函数
def put_seed():
    for s in seed_url:
        url_queue.put(s)
# 定义网址添加到队列的函数
def put_url(url):
    url_queue.put(url)
# 定义判断队列是否不为空函数
def is_queue_noempty():
    if url_queue.empty():
        return False
    return True
    
# 定义从队列获取URL的函数
def get_url():
    return url_queue.get()
# 定义网页下载函数
def download_url(url):
    text = "";
    # 此处为下载代码
    pass
    return text
# 定义网页解析函数
def analysis(text):
    # 此处为网页内容解析代码
    pass
    # 网页内容处理与存储代码
    process()
    # 添加新URL到队列
    pass
# 定义网页内容处理与存储函数
def process(objec=None):
    # 此处为网页内容处理与存储代码
    pass
  
if __name__ == "__main__":
    
    print("------启动爬虫------")
    # 种子URL加入队列
    put_seed()
    # 循环爬取队列的URL
    while is_queue_noempty():
        # 从队列获取URL
        url = get_url()
        # 下载URL
        text = download_url(url)
        # 解析网页内容
        analysis(text)
        
    # 队列为空,爬虫停止
    print("------爬虫停止------")

用Scrapy实现一个简单的爬虫

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。应用框架提供了很多工具和程序,让我们可以轻松开发商业化爬虫,商业化爬虫是指实用的爬虫程序。

下面用Scrapy实现一个简单的爬虫。

(1)创建爬虫项目

使用Scrapy实现爬虫,需要创建一个新的Scrapy项目。创建一个Scrapy项目非常简单,使用Scrapy命令行工具就可以创建Scrapy项目,Scrapy命令行工具可以运行在Windows的命令行窗口或Linux的终端窗口。

运行命令行工具的语法如下:

scrapy < command > [options] [args]

其中,scrapy是工具名称,command是命令,options是命令的选项,args是命令需要的参数,options和args是可选的,依据命令的要求传入。

下面介绍三个主要的命令,创建项目命令、爬虫创建命令和运行项目爬虫命令,因为这三个命令是马上要用到的。其它命令会专门安排一个小节介绍。

创建项目命令

创建项目的语法如下:

scrapy startproject < project_name >

其中startproject是创建项目的命令名称,project_name是项目名称。例如:要创建一个爬取百度新闻网站数据的爬虫,项目名称可以是newsbaidu。

创建newsbaidu项目的命令如下:

scrapy startproject newsbaidu

爬虫创建命令

爬虫创建命令用于在项目中创建一个爬虫,爬虫的英文名称spider。这是创建spider的一种快捷方法,该命令可以使用提前定义好的模板来生成spider,也可以自己创建spider的源码文件。

爬虫创建命令的语法如下:

scrapy genspider [-t template] < name > < domain >

其中genspider是爬虫创建命令的命令名称,template用来设置爬虫源代码的模板名称,这是一个可选项,采用scrapy的默认爬虫模板即可,name是爬虫名称,domain是该爬虫要爬取的网站域名。

运行项目爬虫命令

一个scrapy项目可以运行多个爬虫,运行项目爬虫命令的语法如下:

scrapy crawl < spider >

其中crawl是运行项目爬虫命令的名称,spider是爬虫名称,也就是使用爬虫创建命令创建的爬虫名称。

创建爬虫项目及爬虫

在Windows命令行窗口,将存储项目文件的目录设置为当前目录,使用scrapy工具的startproject命令创建爬虫项目newsbaidu,项目名称也可以是其它名称,在Windows命令行窗口输入下面的命令:

scrapy startproject newsbaidu

在项目中创建爬虫spider_newsbaidu,设置项目所在目录为当前工作目录,在Windows命令行窗口输入下面的命令:

scrapy genspider spider_newsbaidu https://news.baidu.com

(2)定义要抓取的数据

开发爬虫的目的是要爬取网站数据,并提取出结构化数据。要做的第一步工作就是根据要爬取的网站内容构成,定义一个结构化数据,存储从网站提取的数据。

在scrapy中,通过scrapy Items来完成结构化数据的定义。在scrapy创建的爬虫项目中,items.py文件就是一个Items,在Items可以定义要爬取的数据。

例如:要抓取百度新闻网站(news.baidu.com)的热点新闻条目,并获取新闻条目的文章标题、文章链接数据。

可以在项目的items.py文件中定义下面的数据结构:

# 导入scrapy库
import scrapy
#自定义NewsbaiduItem用于存储爬虫所抓取的字段内容
class NewsbaiduItem(scrapy.Item):
    # 定义要爬取的数据:
    # 文章标题
    news_title = scrapy.Field()
    # 文章链接
    news_link = scrapy.Field()

NewsbaiduItem类继承scrapy.Item类,它是一个Scrapy Items,它定义了两个数据字段,分别是news_title和news_link。

类似这样的Scrapy Items可以定义多个,以适应爬取不同的网站数据。

(3)编写一个爬虫程序

定义了存储爬取数据的Scrapy Items,就可以开始编写爬虫程序了。首先要确定百度新闻网站的起始页,也就是百度新闻网站的种子URL。

爬虫的种子URL:www.news.baidu.com

种子URL是百度新闻网站的英国威廉希尔公司网站 ,需要查看百度新闻网站的英国威廉希尔公司网站 源码,确定提取新闻条目的规则,编写XPath表达式。

如何查看网页源码?

使用浏览器打开百度新闻网站的英国威廉希尔公司网站 ,单击鼠标右键,在弹出的菜单中选择“查看网页源代码”命令,不同浏览器可能有不同的命令名称。

观察网页源代码,找出数据提取规则

观察英国威廉希尔公司网站 源代码发现,新闻条目的源代码一般都通过下面的超链接标签实现:

< a href="https://3w.huanqiu.com/a/9eda3d/3zT0a2ZsWaC?agt=8" 
mon="ct=1&a=2&c=top&pn=15" 
target="_blank" >
英国将法国荷兰列入隔离清单,法国:将采取“对等措施”
< /a >

其中,“a”是超链接标签,也称为a标签。“href”是超链接的目标属性,“mon”应是百度新闻网站自定义的一个超链接属性,每个新闻条目的a标签都带有mon属性,通过a标签的mon属性可以和网页的其它a标签区分开。

提取新闻条目的XPath表达式如下:

//a[contains(@mon,'ct=1')]

a标签的mon属性值的“&”是转义符,表示这是一个“&”字符,在XPath表达式中只有判断mon属性值包含字符串“ct=1”就可以提取网页所有的新闻条目。

编写爬虫代码

项目spiders目录下的spider_newsbaidu.py是scrapy创建的一个爬虫模板文件,可以在此基础上修改代码。

模板文件代码如下:

import scrapy
class SpiderNewsbaiduSpider(scrapy.Spider):
    name = 'spider_newsbaidu'
    allowed_domains = ['https://news.baidu.com']
    start_urls = ['https://news.baidu.com/']
    def parse(self, response):
        pass

SpiderNewsbaiduSpider类继承scrapy.Spider类。属性name是爬虫名称,该名称可用于运行项目爬虫的crawl命令;属性allowed_domains是要爬取的网站域名,start_urls是种子URL,start_urls是一个列表对象,可以定义多个种子URL。

在SpiderNewsbaiduSpider类可以编写爬取网站的代码,从下载的网页代码中提取超链接,加入爬取队列,以及从网页的内容中提取结构化数据。

类方法parse(response)用于解析网页内容,提取网页的超链接和结构化数据。该方法是一个回调函数,会被Request对象调用,Request对象是向网页发出请求访问的对象,该对象会返回一个response对象,并调用parse(response)方法对response对象进行处理。

传入的参数是response对象,response对象封装了爬虫从网站爬取的内容,通过response对象可以获取爬取的网页内容。

修改后的爬虫代码如下:

import scrapy
# 导入scrapy选择器
from scrapy.selector import Selector
# 导入NewsbaiduItem
from newsbaidu.items import NewsbaiduItem
class SpiderNewsbaiduSpider(scrapy.Spider):
    name = 'spider_newsbaidu'
    allowed_domains = ['https://news.baidu.com']
    start_urls = ['https://news.baidu.com/']
    def parse(self, response):
        # 获取爬取下来的网页内容
        html = response.text
        # 使用xpath表达式搜寻指定的a标签节点,节点以列表方式返回
        item_nodes = response.xpath("//a[contains(@mon,'ct=1')]").extract()
        # 遍历节点
        for item_node in item_nodes:
            # 使用xpath表达式获取节点的href属性值
            a_href = Selector(text=str(item_node)).xpath('//@href').extract()
            # 使用xpath表达式获取节点的文本内容
            a_text = Selector(text=str(item_node)).xpath('//text()').extract()
            # 实例化NewsbaiduItem对象
            item = NewsbaiduItem()
            item["news_title"] = a_text
            item["news_link"] = a_href
            # 使用yield语句返回item给parse的调用者
            yield item

主要修改了parse()方法,在parse()方法内,通过response对象的text属性获取scrapy下载的网页内容,通过response对象的xpath()方法执行XPath表达式选取网页节点或节点文本,将提取的网页数据存储到NewsbaiduItem对象。

parse()方法使用了yield语句,因此parse()方法是一个生成器函数,当parse()方法的调用者需要一个迭代对象时,parse()方法会返回这个迭代对象。

parse()方法返回的迭代对象主要是两类:一类是scrapy Items类型的实例对象;一类是scrapy Request类型的实例对象,Request对象封装了请求的URL。

(4)运行爬虫

当前创建的SpiderNewsbaiduSpider爬虫还是非常简单的,在爬虫内并没有处理网页内新闻条目外的超链接,因此爬虫处理完该网页内容后,就会自行结束爬取过程。随着对scrapy框架的深入了解,会逐渐完善SpiderNewsbaiduSpider爬虫。

现在可以运行爬虫了,爬取的数据暂时存储到json文件,在后面的课程会存储到数据库。

在Windows命令行窗口,将当前目录切换到项目的根目录,输入下面的命令:

scrapy crawl spider_newsbaidu -o items.json

其中spider_newsbaidu是爬虫名称,选项-o是将Items输出到文件,选项-o后面的参数是文件名称。

执行运行爬虫的命令后,爬虫爬取的数据会存储到项目根目录下的items.json文件,可以使用记事本查看items.json文件内容。

若items.json文件的中文内容显示为文字编码,需要在setting.py文件中添加FEED_EXPORT_ENCODING配置项,该配置项用于设置输出文件的字符编码方式,scrapy输出文件的默认字符编码是ASCII。

通过在setting.py文件添加下面的配置项将scrapy输出文件字符编码设置为utf-8。

FEED_EXPORT_ENCODING = 'utf-8'

** Scrapy爬虫的工作机制**

基于当前学到的scrapy知识,整理出scrapy的工作机制,在后面的课程会逐步完善scrapy的工作机制。

爬虫

Scrapy引擎是Scrapy框架的核心,它可以启动多个爬虫,并管理爬虫的运行。

它会将爬虫提取的Request对象放入到Scrapy调度器(可以把Scrapy调度器看作是URL队列管理),同时它会调用Items数据处理器处理爬虫提取的Items数据。

Scrapy引擎会维持爬虫的运行,维持爬虫运行的机制就是不断从URL队列管理器获取Request对象,调用下载管理器向Request对象指定的URL发出Request请求,下载URL所在服务器返回的内容,并返回Responses对象。

Request对象会回调在Request对象设置的回调函数,并传入Responses对象。若Request对象没有设置回调函数,将会调用Spider的parse()方法。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分