简介:本文主要记录了学习Scrapy框架的成果,以及Selenium模拟浏览器和SQLite数据库的简单应用。
需求:利用Scrapy框架爬取<网易新闻>四大常用板块(国内、国际、军事、无人机)首页的数据,包括标题、来源以及内容,并存储到数据库中。
提示:以下是本篇文章正文内容,下面案例可供参考
1.Scrapy简介
(1)Scrapy是适用于Python的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。
(2)Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
(3)Scrapy最吸引人的地方就在于它是一个框架,任何人都可以根据需求方便快捷的修改。
2.Scrapy架构
Scrapy Engine(引擎):负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
Scheduler(调度器):它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理。
Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)。
Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
Downloader Middlewares(下载中间件):一个可以自定义扩展下载功能的组件。
Spider Middlewares(Spider中间件):一个可以自定扩展和操作引擎和Spider中间通信的功能组件。
1.什么是Selenium?
(1)Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样,其中支持的浏览器包括IE,Firefox,Safari,Chrome等。Selenium 是一套完整的web应用程序测试系统,包含了测试的录制Selenium IDE),编写及运行(Selenium Remote Control)和测试的并行处理(Selenium Grid)。
(2)Selenium的核心Selenium Core基于JsUnit,完全由JavaScript编写,因此可以用于任何支持JavaScript的浏览器上。
(3)Selenium可以模拟真实浏览器,自动化测试工具,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。
Selenium的基本用法
from selenium import webdriver # 导入库
bro = webdriver.Chrome(executable_path='chromedriver.exe') # 声明浏览器
url = 'https:www.baidu.com'
bro.get(url) # 打开浏览器预设网址
print(bro.page_source) # 打印网页源代码
bro.quit() # 关闭浏览器
上述代码运行后,会自动打开Chrome浏览器,并登陆百度打印百度首页的源代码,然后关闭浏览器。
2.什么是SQLite?
(1)SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,您不需要在系统中配置。
(2)就像其他数据库,SQLite 引擎不是一个独立的进程,可以按应用程序需求进行静态或动态连接。SQLite 直接访问其存储文件。
SQLite的基本用法
import sqlite3
conn = sqlite3.connect('wudilibai.db')
cur = conn.cursor()
sql = 'insert into libai (title, content) values (?, ?)'
data = ('千年之狐', '十步杀一人,千里不留行。')
cur.execute(sql, data)
conn.commit()
cur.close()
conn.close()
上述代码运行后,会自动将data里的数据传入到名叫wudilibai的数据库里。
代码如下:
import scrapy
from selenium import webdriver
from wangyixinwen.items import WangyixinwenItem
class WangyiSpider(scrapy.Spider):
name = 'wangyi'
# allowed_domains = ['wangyi.com']
start_urls = ['https://news.163.com/']
model_urls = [] # 存储四个板块对应详情页的url
# 实例化一个浏览器对象
def __init__(self):
super().__init__()
self.bro = webdriver.Chrome(executable_path='chromedriver.exe') # 只打开一次模拟浏览器
def parse(self, response):
li_list = response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li')
model_list = [3, 4, 6, 8]
for index in model_list:
model_url = li_list[index].xpath('./a/@href').extract_first()
self.model_urls.append(model_url)
# 依次对每一个板块对应的页面进行请求
for url in self.model_urls: # 对每一个板块的url进行请求发送
yield scrapy.Request(url=url, callback=self.parse_model)
# 每一个板块对应的新闻标题相关的内容都是动态加载
def parse_model(self, response): # 解析每一个板块页面中对应新闻的标题和新闻详情页的url
div_list = response.xpath('/html/body/div[1]/div[3]/div[4]/div[1]/div/div/ul/li/div/div')
for div in div_list:
title = div.xpath('./div/div[1]/h3/a/text()').extract_first()
new_detail_url = div.xpath('./div/div[1]/h3/a/@href').extract_first()
item = WangyixinwenItem() # 实例化一个item对象
item['title'] = title # 把抓取到的title放入到item对象中
# 对新闻详情页的url发起请求,meta是一个字典,用来把item对象传出去
yield scrapy.Request(url=new_detail_url, callback=self.parse_detail, meta={
'item': item})
def parse_detail(self, response): # 解析新闻内容
sourse = response.xpath('//*[@id="ne_article_source"]/text()').extract_first()
content = response.xpath('//*[@id="endText"]/p/text()').extract()
# ''.join()把列表中的元素连接成一个字符串,strip()去掉换行,replace(" ", "")去掉看空格
content = ''.join(content).strip().replace(" ", "")
item = response.meta['item']
item['sourse'] = sourse
item['content'] = content
yield item # 将item对象提交给piplelines(管道文件),用于持久化存储
def closed(self, spider):
self.bro.quit() # 关闭模拟浏览器
代码如下:
import scrapy
class WangyixinwenItem(scrapy.Item):
title = scrapy.Field()
sourse = scrapy.Field()
content = scrapy.Field()
代码如下:
from scrapy.http import HtmlResponse
from time import sleep
class WangyixinwenDownloaderMiddleware:
def process_request(self, request, spider):
# Called for each request that goes through the downloader
# middleware.
# Must either:
# - return None: continue processing this request
# - or return a Response object
# - or return a Request object
# - or raise IgnoreRequest: process_exception() methods of
# installed downloader middleware will be called
return None
def process_response(self, request, response, spider): # spider爬虫对象
bro = spider.bro # 获取了在爬虫类中定义的浏览器对象
# 挑选出指定的响应对象进行篡改
# 通过url指定request
# 通过request指定response
if request.url in spider.model_urls:
bro.get(request.url) # 五个板块对应的url进行请求
sleep(3) # 睡眠3秒,预防反爬虫
page_text = bro.page_source # 包含了动态加载的新闻数据
# response是四大板块对应的响应对象
# 针对定位到的这些response进行篡改
# 实例化一个新的响应对象(符合需求:包含动态加载出的新闻数据),替代原来旧的响应对象
# 如何获取动态加载出的新闻数据?(基于selenium便捷的获取动态加载数据)
new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
return new_response
else:
#response是其他请求对应的响应对象
return response
def process_exception(self, request, exception, spider):
# Called when a download handler or a process_request()
# (from other downloader middleware) raises an exception.
# Must either:
# - return None: continue processing this exception
# - return a Response object: stops process_exception() chain
# - return a Request object: stops process_exception() chain
pass
代码如下:
import sqlite3
class Sqlite3Pipeline(object):
def open_spider(self, spider):
print('开始导入数据库。。。')
self.conn = sqlite3.connect('E:\学习研究\python爬虫\爬虫课件\南茹旅舍\wangyixinwen\wangyi_news.db')
self.cur = self.conn.cursor()
def process_item(self, item, spider):
insert_sql = "insert into wangyi(标题, 来源, 内容) " \
"values (?, ?, ?)"
data = (item['title'], item['sourse'], item['content'])
self.cur.execute(insert_sql, data)
self.conn.commit()
return item
def close_spider(self, spider):
print('导入数据库完毕!!!')
self.cur.close()
self.conn.close()
代码如下:
BOT_NAME = 'wangyixinwen'
SPIDER_MODULES = ['wangyixinwen.spiders']
NEWSPIDER_MODULE = 'wangyixinwen.spiders'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# 运行栏只显示错误信息,看起来比较方便清晰
LOG_LEVEL = 'ERROR'
# 打开下载中间件
DOWNLOADER_MIDDLEWARES = {
'wangyixinwen.middlewares.WangyixinwenDownloaderMiddleware': 543,
}
# 打开管道文件
ITEM_PIPELINES = {
'wangyixinwen.pipelines.Sqlite3Pipeline': 300,
}
代码如下:
# -*- coding: utf-8 -*-
# @Time: 2020/8/18 19:01
# @Author: Ricky Rau
# @Email: [email protected]
from scrapy import cmdline
cmdline.execute('scrapy crawl wangyi'.split())
上述代码的作用和 Scrapy Shell 里的 scrapy crawl wangyi 的作用是一样,个人认为更加方便。
可以下载一个DB Browser for SQLite软件,用来查阅SQLite数据库,从软件中可以清晰的看到所爬取的数据(标题,来源以及内容)。
本文主要通过scrapy框架结合selenium、sqlite3对网易新闻中四大板块的标题、来源以及内容进行的爬取,过程中总会遇到大大小小的问题,有可能一个字母打错了或者一个路径写错了,都不要放弃,坚持总会有回报。