实验五Elasticsearch+Kibana展示爬虫数据
安装elasticsearch-rtf
Elasticsearch-rtf相比于elasticsearch而言多加了一些插件,因此我们选择安装Elasticsearch-rtf是一个不错的选择。在安装之前我们需要安装java的apk,并且要求版本在8.0或以上,下载地址 https://github.com/medcl/elasticsearch-rtf, 下载完后,进入bin目录 命令行输入
./elasticsearch
即可启动 在浏览器中访问https://127.0.0.1:9200查看结果
安装elasticsearch-head
Elasticsearch-head是一个可视化的管理工具,利用它我们可以清楚的看到elasticsearch中的数据,下载地址 https://github.com/mobz/elasticsearch-head
在终端输入下列命令
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
需要注意的是,在安装前需要测试是否能使用npm命令,npm是nodejs的包管理工具,类似于Java的maven,Python的pip,因此我们需要下载nodejs 下载地址 https://www.nodejs.org 由于npm的中央服务器在国外,速度太慢,因此我们使用淘宝的npm镜像cnpm 下载cnpm命令
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
安装完之后我们需要配置一下config目录下的.yml文件 输入如下四行
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE
http.cors.allow-headers: "X-Requested-With, Content-Type, Content-Length, X-User"
然后重启一下elasticsearch服务,就可以在9100端口看到elaticsearch连接成功了
安装kibana
下载地址 https://www.elastic.co/downloads/kibana 需要注意的是kibana的版本号必须与elasticsearch对应 我们在面板的info中可以查询elasticsearch版本,当前的版本为5.1.1
下载好对应的版本后,进入bin目录 在终端输入
./kibana
即可运行,在浏览器访问 http://localhost:5601
安装Django
直接使用pip命令安装
pip install django==2.2.2
安装Scrapy
直接使用pip命令安装
pip install scrapy
安装Chromedriver
我们使用Selenium的时候需要用到谷歌浏览器的驱动Chromedriver,下载地址:https://chromedriver.storage.googleapis.com/index.html, 需要找到与谷歌浏览器对应的版本下载,下载完成后放入到/usr/bin或/usr/local/bin目录即可完成安装
sudo mv ./chromedriver /usr/bin
之后在terminal终端输入chromedriver,若显示如下信息,证明安装成功
charles.:~/ $ chromedriver [10:21:40]
Starting ChromeDriver 81.0.4044.138 (8c6c7ba89cc9453625af54f11fd83179e23450fa-refs/branch-heads/4044@{#999}) on port 9515
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
再通过pip命令安装Selenium
pip install selenium
通过以下代码测试是否可以成功驱动谷歌浏览器
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('http://www.baidu.com')
若可以正常打开浏览器并访问百度首页,证明安装成功
安装MongoDB
在Mac下安装MongoDB可采用Homebrew方式
brew install mongodb
然后创建一个新的文件夹/data/db,用于存放数据
启动MongoDB
brew services start mongodb
sudo mongod
停止和重启MongoDB命令
brew services stop mongodb
brew services restart mongodb
(一)编程实现通用爬虫
无需登录或可抓包模拟登陆
原先我们爬每一个网站都需要单独写一个spider, 这个spider中存在name
,start_urls
,allowed_domains
,rules
等字段,我们通常要完成下面几步:
- 通过scrapy命令新建一个spider
- 定义一个爬取字段信息的字典
- 通过分析网页找到定位规则
- 实现parse()解析字段的函数
而这些步骤相对比较固定,因此我们可以新建一个universal爬虫,通过读取配置 文件的方式来动态生成一个spider,省去了重复创建spider的麻烦
1、在终端启动爬虫命令 在终端输入以下命令,就可以启动爬虫
python3 run.py spider_name
2、读取配置文件,启动爬虫进程 run()函数读取对应spider_name的配置文件后,启动相应的爬虫进程
import sys
from scrapy.utils.project import get_project_settings
from spds.utils import get_config
from scrapy.crawler import CrawlerProcess
def run():
# 获取爬虫名称
name = sys.argv[1]
# 用户配置,一个json文件
custom_settings = get_config(name)
# 使用通用爬虫
spider = custom_settings.get('spider', 'universal')
# 项目配置
project_settings = get_project_settings()
settings = dict(project_settings.copy())
# 合并用户配置和项目配置
settings.update(custom_settings.get('settings'))
# 启动爬虫
process = CrawlerProcess(settings)
process.crawl(spider, **{'name': name})
process.start()
if __name__ == '__main__':
run()
3、run()函数需要调用get_config()方法 读取配置文件的方法为utils.py中的get_config(),它会根 据传入的爬虫名name,去config目录下寻找对应的爬虫的json文件
from os.path import realpath, dirname
import json
def get_config(name):
path = dirname(realpath(__file__)) + '/configs/' + name + '.json'
with open(path, 'r', encoding='utf-8') as f:
return json.loads(f.read())
4、json文件的结构
{"spider": "universal",
"website": "第一财经网",
"type": "新闻",
"index": "http://yicai.com",
"settings": {
"USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
},
"start_urls":{
"type": "static",
"value" :["http://yicai.com/news", "http://yicai.com/data"]
},
"allowed_domains": [
"yicai.com"
],
"rules": "yicai",
"item": {
"class": "NewsItem",
"loader": "ChinaLoader",
"attrs": {
"title": [
{
"method": "xpath",
"args": [
"//div[@class=\"title f-pr\"]/h1//text()"
]
}
],
"url":[
{
"method": "attr",
"args": [
"url"
]
}
],
"website":[
{
"method":"value",
"args":[
"第一财经网"
]
}
]
}
}
}
Selenium + Webdriver
- 信号
由于使用Selenium进行驱动常用的操作无非是滚动、点击、 输入数据的有序组合,那么我就把它们封装成函数,然后通过 信号值分别调用对应的操作,最后只需要规定它们的顺序来完成 用户想要的控制流程.
信号1 滚动
信号2 点击
信号3 输入
所有操作浏览器的流程都封装在一个叫做SeleniumMiddleware
的中间件来实现, 当驱动程序工作完成后,将采集到的数据返回给Spider中的parse_item()
函数 进行解析,最后再通过MongoPipeline
管道存入MongoDB数据库
- 任务
和之前的通用爬虫一样,将所有可配置的参数都抽离出来,形成一个json文件,其中 不同之处在于这里的tasks
字段
"tasks": [
{
"order": 1,
"action": {
"signal": 1,
"args": "",
"text": ""
},
"attrs": {}
},
{
"order": 2,
"action": {
"signal": 2,
"args": "//li[@data-anchor=\"#comment\" and contains(.,\"商品评价\")]"
},
"attrs": {
"mark": "//div[@class=\"comment-percent\"]"
}
},
{
"order": 3,
"action": {
"signal": 2,
"args": "//li[@data-anchor=\"#detail\" and contains(.,\"商品介绍\")]"
},
"attrs": {
"product_name": "//ul[@class=\"parameter2 p-parameter-list\"]/li[contains(.,\"商品名称\")]",
"product_code": "//ul[@class=\"parameter2 p-parameter-list\"]/li[contains(.,\"商品编号\")]",
"product_weight": "//ul[@class=\"parameter2 p-parameter-list\"]/li[contains(.,\"商品毛重\")]"
}
}
]
所有的任务都规定在这个列表中,每个元素是一个字典类型,代表一个task任务,我们规定一个 task任务拥有以下3个属性
- order 用来规定任务task发生的顺序
- action 表示要采取的动作类型,通过signal来确定,每个信号对应的动作见信号
- attrs表示动作结束后所需要获取的字段,它的值是一个字典类型,key为字段名称,值为提取该字段的xpath规则
(二)通过Scrapy框架中的Pipeline将数据写入MongoDB
1、在项目中定义一个MongoPipeline
# pipeline.py
class MongoPipeline():
def __init__(self, mongo_uri, mongo_db, mongo_coll):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
self.mongo_coll = mongo_coll
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DB'),
mongo_coll=crawler.settings.get('MONGO_COLL')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def process_item(self, item, spider):
self.db[self.mongo_coll].insert(dict(item))
return item
def close_spider(self, spider):
self.client.close()
class SpdsPipeline(object):
def process_item(self, item, spider):
return i
2、在settings.py中设定优先顺序
# settings.py
ITEM_PIPELINES = {
# 'spds.pipelines.SpdsPipeline': 300,
'spds.pipelines.MongoPipeline': 301,
}
3、添加MongoDB参数
# MONGO_URI = 'mongodb://jizhu:jizhu123@119.29.214.139:27017' # 腾讯云服务器
MONGO_URI = 'localhost'
MONGO_DB = 'articles'
MONGO_COLL = 'yicai'
(三)搭建本地Elasticsearch集群
其实在Elasticsearch搭建本地集群非常简单,只需要多开几个终端进程,在命令行附带一些额外信息即可
bin/elasticsearch (默认端口9200)
bin/elasticsearch -Ehttp.port=8200 -Epath.data=node2
bin/elasticsearch -Ehttp.port=7200 -Epath.data=node3
通过上面的命令就可以在端口为9200
、8200
和7200
上各开一个Elasticsearch节点
(四)编写程序将MongoDB数据写入Elasticsearch
1、最终的数据需要进行清洗、分词等处理并放入Elasticsearch中进行索引
# lagou_es.py
...
client = pymongo.MongoClient('127.0.0.1', 27017)
db = client['lagou']
collection_list = [ 'jobs', 'quanzhangongchengshi','qukuailian', 'tuxiangchuli', 'tuxiangshibie', 'yuyinshibie']
for coll in collection_list:
print('正在转换::' + coll)
collection = db[coll]
ls = list(collection.find())
for item in ls:
item['website'] = '拉勾网'
job = JobType()
job.website = item['website']
job.url = item.get('url','')
job.job_name = item.get('job_name','')
job.company = item.get('company','')
job.salary = item.get('salary','')
job.city = item.get('city','')
job.experience = item.get('experience','')
job.education = item.get('education','')
job.job_type = item.get('job_type','')
job.publish_time = item.get('publish_time','')
job.job_advantage = item.get('job_advantage','')
job.job_desc = item.get('job_desc','')
job.job_addr = item.get('job_addr','')
job.c_area = item.get('c_area','')
job.c_dev = item.