当前百度新闻爬虫项目将爬取的数据输出到了JSON文件,在实际应用中,一般会将爬取的数据存储到数据库,方便后续程序对爬取的数据进行分析和处理。
若希望百度新闻爬虫项目将爬取的数据存储到数据库,该做哪些工作呢?数据库服务器的地址、登录账号和密码等信息要放置到项目的什么位置呢?
1、初步认识配置文件
现在就要用到Scrapy的配置文件了,配置文件就在项目的根目录下,文件名称是settings.py。
爬虫项目创建完成后,settings.py的主要内容如下:
BOT_NAME = 'newsbaidu' SPIDER_MODULES = ['newsbaidu.spiders'] NEWSPIDER_MODULE = 'newsbaidu.spiders' ROBOTSTXT_OBEY = True # 项目新添加的配置项 FEED_EXPORT_ENCODING = 'utf-8'
配置文件的注释行没有列出来,其中一些默认的配置项也被注释了,若要用到这些配置项,需要把注释去掉。
配置项是一个键值对,键是配置项的名称,值是配置项的内容。Scrapy框架应用配置文件里的多个配置项来定制或扩展爬虫的行为和功能,多个配置项为一个配置组,主要有项目信息、数据爬取方式、爬取日志与统计、爬取性能、文件下载、管道、Scrapy扩展等配置组。
例如在上面的配置文件中,项目信息配置组有下面的配置项:
BOT_NAME = 'newsbaidu' SPIDER_MODULES = ['newsbaidu.spiders'] NEWSPIDER_MODULE = 'newsbaidu.spiders'
配置项BOT_NAME配置了爬虫项目的名称,该名称也是日志记录的名称;配置项SPIDER_MODULES存储了项目拥有的爬虫模块,配置项的值是一个列表对象,可以存储多个爬虫模块;配置项NEWSPIDER_MODULE存储了使用genspide命令创建新爬虫时,爬虫程序文件存储的包路径。
项目添加的配置项FEED_EXPORT_ENCODING用于解决中文编码问题,该配置项可以设置输出文件的字符编码方式,scrapy输出文件的默认字符编码是ASCII,ASCII编码不能表示中文字符,因此在输出的JSON文件内,中文字符会显示为16进制的字符编码,要解决这个问题,就需要在在setting.py文件添加配置项FEED_EXPORT_ENCODING,将scrapy输出文件字符编码设置为utf-8。
2、 输出爬虫运行日志
运行日志就是记录爬虫在运行过程中的状态、行为、异常信息等内容,通过分析运行日志,可以实现对爬虫的运行状态的分析、调试及错误定位。
Scrapy框架默认是不输出运行日志的,要让爬虫程序输出运行日志,需要做下面一些工作。
一、在配置文件内添加日志配置项
Scrapy对日志的输出信息进行了等级划分,共有五个等级:
1、CRITICA:严重错误(critical) 2、ERROR:一般错误(regular errors) 3、 WARNING:警告信息(warning messages) 4 、INFO:一般信息(informational messages) 5 、 DEBUG:调试信息(debugging messages)
数字越小等级越高,最高等级是发生严重错误,最低等级是调试信息,日志输出信息划分等级可以对输出的日志信息进行调整,避免输出不必要的日志信息。
若是程序在调试过程,可以设置日志等级为DEBUG,所有等级的日志信息都会输出到日志文件;若是程序进入正常运行,可以设置日志等级为WARNING,WARNING及以上的等级日志信息会被输出到日志文件。
日志输出等级的设置放置在配置文件内,在配置文件尾部添加LOG_LEVEL配置项:
# 日志配置 LOG_LEVEL ='INFO' 日志要输出到文件,在配置文件内还要配置日志输出文件的路径和文件名称。配置文件路径和名称的配置项是LOG_FILE。 # 日志配置 LOG_LEVEL ='INFO' LOG_FILE ='./baidnews.log'
“./baidnews.log”是在当前程序运行的目录下输出baidnews.log日志文件。该配置项将会导致日志信息输出到文件而不是控制台。
二、在代码内输出日志信息
Python提供的logging日志模块可以输出日志信息。在spider_newsbaidu.py文件内添加下面的代码:
# 导入日志模块
import logging
# 创建日志实例对象
logger = logging.getLogger("SpiderNewsbaiduSpider")logging模块的getLogger()方法获取Logger实例对象,传入的字符串参数设置输出日志的模块名称。
在SpiderNewsbaiduSpider类parse()方法内部的for循环结构内添加下面的代码:
logger.info(str(item_node))
info()方法是Logger实例对象输出info级别的信息。
spider_newsbaidu.py完整代码如下:
import scrapy
# 导入scrapy选择器
from scrapy.selector import Selector
# 导入NewsbaiduItem
from newsbaidu.items import NewsbaiduItem
# 导入BaiduNewsLoader
from newsbaidu.newsitemload import BaiduNewsLoader
# 导入日志模块
import logging
# 创建日志实例对象
logger = logging.getLogger("SpiderNewsbaiduSpider")
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表达式搜寻新闻类别超链接标签
category_node = response.xpath("//div[@id='channel-all']/div/ul/li[position()>1]/a/@href").extract()
for request_node in category_node:
url = response.urljoin(request_node)
request = scrapy.Request(url,callback=self.parse_category,dont_filter=True)
yield request
# 使用xpath表达式搜寻指定的a标签节点,节点以列表方式返回
item_nodes = response.xpath("//a[contains(@mon,'ct=1')]").extract()
# 遍历节点
for item_node in item_nodes:
# 输出info级别的日志信息
logger.info(str(item_node))
# 实例化BaiduNewsLoader对象
loader = BaiduNewsLoader(item=NewsbaiduItem(), selector=Selector(text=str(item_node)))
# 提取并清洗news_title数据项
print(loader.add_xpath("news_title","//text()"))
# 提取并清洗news_link数据项
loader.add_xpath("news_link","//@href")
# 获取收集的news_title数据项的值
value = loader.get_collected_values("news_title")
# 若value不为None,调用yield语句返回Item数据项
if value:
yield loader.load_item()
# 处理类别网页的回调方法
def parse_category(self, response):
html = response.text
# 解析新闻类别名称
category = response.xpath("//li[contains(@class,'current active')]/a/text()").extract()
# 使用xpath表达式搜寻指定的a标签节点,节点以列表方式返回
item_nodes = response.xpath("//a[contains(@mon,'col') and not(contains(@mon,'col=carouse'))]").extract()
# 遍历节点
for item_node in item_nodes:
# 实例化BaiduNewsLoader对象
loader = BaiduNewsLoader(item=NewsbaiduItem(), selector=Selector(text=str(item_node)))
pre_category = ["(" + category[0] + ")"]
# 添加新闻类别名称
loader.add_value("news_title",pre_category)
# 天机新闻条目标题
loader.add_xpath("news_title","//text()")
# 使用Selector选择器获取超超链接的文本
loader.add_xpath("news_link","//@href")
# 获取收集的news_title数据项的值
value = loader.get_collected_values("news_title")
# 若value不为None,调用yield语句返回Item数据项
if value:
yield loader.load_item()3、 读取配置项
在一些情况下,需要在程序内读取配置文件的配置项。Scrapy框架的utils.project模块提供了get_project_settings()函数,用于获取操作配置文件的字典对象。
访问配置文件配置项的案例代码:
#导入settings配置读取函数 from scrapy.utils.project import get_project_settings # 获取操作配置文件的字典对象 settings = get_project_settings() # 读取 LOG_FILE配置项 logfile=settings[' LOG_FILE ']
读取配置项的案例代码参见后面的课程案例。