分布式爬虫搭建毕设

理清要求

  1. scrapy-redis 要求

image-20220503203749714

image-20220503204826387

  1. 通过redis 调度内容,注意redis修改需要4个组件

    https://jqiange.github.io/Scrapy-Redis%E5%88%86%E5%B8%83%E5%BC%8F%E7%88%AC%E8%99%AB/

    然后根据 request 中的优先级,来决定该入哪个队列,出列时则按优先级较小的优先出列。由于 Scrapy 原来的 Scheduler 只能处理 Scrapy 自身的队列,不能处理 Redis 中的队列,所以原来的 Scheduler 已经无法使用,应该使用 Scrapy-Redis 的 Scheduler 组件。

    3.redis的自带github路径 https://github.com/rmax/scrapy-redis

    注意不能用json和pickle,只能用string

    Caveat: In python 3.x, the serializer must return strings keys and support
    # bytes as values. Because of this reason the json or msgpack module will not
    # work by default. In python 2.x there is no such issue and you can use
    # 'json' or 'msgpack' as serializers
    

7.关于去重,布隆过滤器

Scrapy 自带去重模块,该模块使用的是 Python 中的集合类型。该集合会记录每个请求的指纹,指纹也就是 Request 的散列值。指纹的计算采用的是 hashlib 的 sha1()方法。计算的字段包含了,请求的 Method,URL,Body,Header 这几个内容,这些字符串里面只要里面有一点不同,那么计算出来的指纹就是不一样的。也就是说,计算的结果是加密后的字符串,这就是请求指纹。通过加密后的字符串,使得每个请求都是唯一的,也就是指纹是惟一的。并且指纹是一个字符串,在判断字符串的时候,要比判断整个请求对象容易。所以采用了指纹作为判断去重的依据。

Scrapy-Redis 要想实现分布式爬虫的去重功能,也是需要更新指纹集合的,但是不能每个爬虫维护自己的单独的指纹集合。利用 Redis 集合的数据结构类型,可以轻松实现分布式爬虫的指纹判重。也就是说:每台主机得到 Request 的指纹去和 Redis 中的集合进行对比,如果指纹存在,说明是重复的,也就不会再去发送请求,如果不曾存在于 Redis 中的指纹集合,就会发送请求,并且将该指纹加入 Redis 的集合中。这样就实现了分布式爬虫的指纹集合的共享

收集资料

和scrapy的传统方式有不同的地方需要变更。

  • 借助 Redis Stack,内存数据存储提供商 Redis 正在将多个Redis模块的功能整合到一个扩展中,以使开发人员能够轻松构建实时应用程序。

    使用 Redis Stack 的开发人员应该会发现使用基于 Redis 的搜索、文档、图形和时间序列功能更容易构建。Redis Stack 于 3 月 23 日发布,由三个组件组成:

    • Redis Stack Server,将开源Redis与RediSearch二级索引和查询引擎、RedisJSON JSON数据类型、RedisGraph可查询属性图数据库、RedisTimeSeries时间序列数据结构、RedisBloom相结合,提供概率数据结构。
    • RedisInsight,用于可视化和优化 Redis 数据的工具。
    • Redis Stack 客户端 SDK,带有 Java、JavaScript 和 Python 中的 Redis 客户端。客户端包括一套对象映射库,其抽象旨在帮助开发人员通过几行代码提高工作效率。

    Redis 模块是可以加载到 Redis 中的动态库。它们使扩展 Redis 功能和实现新命令成为可能,这些命令提供了与核心内部可以完成的功能相当的重要功能。

  • 安装了requirements包后,安装

    • sudo apt install python3-scrapy

  • 三、常见的内置处理器 1、Identity

    不对数据进行处理,直接返回原来的数据

    2、TakeFirst

    返回第一个非空值,常用于单值字段的输出处理

    3、Join

    相当于把列表中的元素拼接起来

    4、MapCompose把几个方法组合起来

跑通测试

image-20220503221732119

Redis Blpop 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

爬虫跑多个crawl,然后process_item跑多个处理模块

爬虫要求

image-20220503230452069

redis中使用了去重和调度

所以会有相关的key-value值存在。

Scrapy 自带去重模块,该模块使用的是 Python 中的集合类型。该集合会记录每个请求的指纹,指纹也就是 Request 的散列值。指纹的计算采用的是 hashlib 的 sha1()方法。计算的字段包含了,请求的 Method,URL,Body,Header 这几个内容,这些字符串里面只要里面有一点不同,那么计算出来的指纹就是不一样的。也就是说,计算的结果是加密后的字符串,这就是请求指纹。通过加密后的字符串,使得每个请求都是唯一的,也就是指纹是惟一的。并且指纹是一个字符串,在判断字符串的时候,要比判断整个请求对象容易。所以采用了指纹作为判断去重的依据。调度在dmoz:dupefilter 中

https://jqiange.github.io/Scrapy-Redis%E5%88%86%E5%B8%83%E5%BC%8F%E7%88%AC%E8%99%AB/

image-20220503232323414

上文中的分布式 URL如下:

https://jqiange.github.io/Scrapy-Redis%E5%88%86%E5%B8%83%E5%BC%8F%E7%88%AC%E8%99%AB/

这里的mysql写的比较好

https://www.jianshu.com/p/77d8fb64cbcd

磁盘扩容

growpart /dev/sda 1
resize2fs /dev/sda1

配置MongoDB

docker run -itd --name mongo -p 27017:27017 mongo:3.4.9 --auth

docker run -itd --name mongo1 -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME:admin -e MONGO_INITDB_ROOT_PASSWORD:123456 mongo --auth

或者不使用auth
默认版本3.4.9,latest就是这个值。原因不明确。这里更新为新的mongodb,再测试pymongo。
docker run -itd --name mongo -p 27017:27017 mongo:5.0.8-focal
db.createUser({ user:'xuan',pwd:'123456',roles:["root"]});
db.dropUser('test')
db.updateUser({ user:'admin',pwd:'123456',roles:["root"]})  //修改密码 并且 //修改角色为只读

授权才可以登录操作用户
> db.auth('test','test')  // 进行test用户授权

实际部署可用环境变量修改。

需要安装指定版本pymongo,默认mongodb的docker 是3.4.2

pip install pymongo==3.12.3

pip install pymongo==4.1.1
添加用户

在dockerfile文件中添加用户https://stackoverflow.com/questions/34559557/how-to-enable-authentication-on-mongodb-through-docker

要添加除 root 之外的自定义用户,请使用入口点可执行脚本(在 $PWD/mongo-entrypoint 目录下,因为它已安装docker-compose到入口点):

#!/usr/bin/env bash
echo "Creating mongo users..."
mongo admin --host localhost -u USER_PREVIOUSLY_DEFINED -p PASS_YOU_PREVIOUSLY_DEFINED --eval "db.createUser({user: 'ANOTHER_USER', pwd: 'PASS', roles: [{role: 'readWrite', db: 'xxx'}]}); db.createUser({user: 'admin', pwd: 'PASS', roles: [{role: 'userAdminAnyDatabase', db: 'admin'}]});"
echo "Mongo users created."

### 目前的方式都是用脚本或者进入dockerfile里面生成用户,如果用

dockerfile和docker-compose书写

1.有两个scrapy镜像+ 两个数据库镜像,两个scrapy镜像都可以生成多个,若要求是多个虚拟机,那么

  1. docker run -d –name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest

  2. 设置好相关值

  3. docker –link redis-stack-server xx

  4. 将两个容器链接允许ping ,然后内部host名这里默认和名称相同

  5. docker run –link redis-stack-server xuan/scrapy-redis:v01

image-20220504121530818

mongo 作为存储后端不放入,单独作为docker daemon存在,docker-compose的yaml文件已经写好。

然后存储到mongodb后端。

alpine 换源

sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
rc-update add docker
rc boot docker
docker run -d \
  --name=deluge \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Asia/Shanghai \
  -e DELUGE_LOGLEVEL=error `#optional` \
  --network=host \
  -v /docker/deluge/config:/config \
  -v /volume1/deluge/downloads:/downloads \
  --restart unless-stopped \
  lscr.io/linuxserver/deluge:2.0.5
  
  docker run -d \
  --name=qbittorrent \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Asia/Shanghai \
  -e WEBUI_PORT=8080 \
  --net=host  \
  -v /docker/qbittorrent/config:/config \
  -v /volume1/qbittorrent/downloads:/downloads \
  --restart unless-stopped \
  linuxserver/qbittorrent:latest
  
bash <(wget -qO- https://git.io/qbox-lite -o /dev/null) -u demouser -p demo123456 --with-ffmpeg -P 1234 --with-bbr --with-deluge --with-mktorrent --with-linuxrar --with-cf --hostname vmserver --reboot


模糊搜索

https://juejin.cn/post/6865223847965097991

配置模糊搜索。

docker-compose 扩容

提前配置好mongoDB

docker start mongo1
docker ps -a
docker-compose scale crawler=3
docker-compose scale processor1=3
docker-compose up --scale crawler=3 --scale processor1=3
docker-compose up --scale processor=3 --scale crawler=3

设置和定义REST接口

全文搜索服务提供以下 REST API 接口:

URLHTTP功能
/1.1/search/selectGET条件查询
/1.1/search/mltGETmoreLikeThis 相关性查询
/1.1/search/analyzeGET分词结果查询

在调用全文搜索的 REST API 接口前,需要首先为相应的 Class 启用搜索。 另外也请参考《存储 REST API 使用指南》中关于 API Base URL、请求格式、响应格式的说明,以及《全文搜索开发指南》的《自定义分词》章节。

条件查询

GET /1.1/search/select REST API 接口提供全文搜索功能。

+https://leancloud.cn/docs/search-rest-api.html

curl -X GET \
  -H "X-LC-Id: {{appid}}" \
  -H "X-LC-Key: {{appkey}}" \
  "https://API_BASE_URL/1.1/search/select?q=dennis&limit=200&clazz=GameScore&order=-score"
 

返回类似:

{
"hits": 1,  
"results": [
  {
    "_app_url": "http://stg.pass.com//1/go/com.leancloud/classes/GameScore/51e3a334e4b0b3eb44adbe1a",
    "_deeplink": "com.leancloud.appSearchTest://leancloud/classes/GameScore/51e3a334e4b0b3eb44adbe1a",
    "_highlight": null,
    "updatedAt": "2011-08-20T02:06:57.931Z",
    "playerName": "Sean Plott",
    "objectId": "51e3a334e4b0b3eb44adbe1a",
    "createdAt": "2011-08-20T02:06:57.931Z",
    "cheatMode": false,
    "score": 1337
  }
],
"sid": "cXVlcnlUaGVuRmV0Y2g7Mzs0NDpWX0NFUmFjY1JtMnpaRDFrNUlBcTNnOzQzOlZfQ0VSYWNjUm0yelpEMWs1SUFxM2c7NDU6Vl9DRVJhY2NSbTJ6WkQxazVJQXEzZzswOw=="
}

查询的参数支持:

思路

先设定一个全局查询的,速度慢,但是简单

/v1/collection1/select/

默认返回所有值。

再添加分页处理

类型转换
        # bson 类型
        datalist = myc1.find_one()
        # 转为str
        d = json_util.dumps(datalist)#
        # str 转为dict ,实际json
        dd = json.loads(d)
        L.append(dd)
        # dict 转json
        return jsonify(L)

Flask 的跨域

pip install flask-cors

from flask_cors import cross_origin

@app.route("/")
@cross_origin()
def helloWorld():
  return "Hello, cross-origin-world!"

vue 表值更新

https://segmentfault.com/q/1010000015667282
可以设置方法,然后在created函数里面调用方法

console.log(response);this.val=response;this.val=this.val.filter(word => word.length > 0)}
这里也可以试试  this.tableData.filter(word => word.length > 0) 好像不要也可以,毕竟没有更新

注意开始测试的流程

  1. 开启mongodb
  2. 开启flask节点,判断cors存在,需要三个值
  3. vue-devtools 判断成立

element-ui

查了好久,才发现这个自动补全框,默认是value,需要添加额外的属性,value-key才行,总结,当与预期不符合,考虑是否有属性没有添加。这里可以考虑不添加搜索框??先添加,再用handle select

handle select

@select=“handleSelect” 是选中某一列触发的事件,在这里item为选中字段所在的对象

            handleSelect (item) {
                this.addTopic.topicId = item.id
                this.addTopic.name = item.name
                this.addTopic.creator = item.creator
            },
搜索内容的处理

如果使用远程搜索下拉内容,由于后端已经使用了模糊查询,这里如果使用原网站的方法匹配中间的字段是无法进行下拉内容的显示的,要么修改原网站的createStateFilter匹配方法,要么直接 cb(results);,显示从后端获取的全部内容。 嗯,我是直接显示后端的搜索内容的,毕竟偷懒偷懒。。。。

好像输入框对值的处理方式不同

Input 为受控组件,它总会显示 Vue 绑定值

通常情况下,应当处理 input 事件,并更新组件的绑定值(或使用v-model)。否则,输入框内显示的值将不会改变。

不支持 v-model 修饰符。

js

箭头函数

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions

配置点云和词云

直接调用所有的数据生成还是,,先在后台调用处理,然后生成图片,不对,这个数据是实时增加的。

应该是在界面处调用函数,函数内部生成所有数据,再进行处理。

直方图是对概率分布的统计

https://www.tutorialspoint.com/matplotlib/matplotlib_histogram.htm

https://zh.wikipedia.org/zh-cn/%E7%9B%B4%E6%96%B9%E5%9B%BE

中文显示设置

https://blog.csdn.net/qq_17753903/article/details/86260276

docker-code-挂载code文件夹便于调试。

静态文件

考虑直接走文件服务器,用docker内部跑两个脚本吧。。。http.server或者配上volume的nginx??

跳转按钮

 <router-link :to="{path:'router中配置的页面路径',query:{参数名: 参数值 }}">
          <el-button size="mini">跳转按钮</el-button>
</router-link>

用router-link 跳转

vue-router版本

这里vue2的版本需要对应

npm install --legacy-peer-deps vue-router@3.5.2

请注意,我们没有使用常规的 a 标签,而是使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。我们将在后面看到如何从这些功能中获益。

router-view#

router-view 将显示与 url 对应的组件。你可以把它放在任何地方,以适应你的布局。

似乎用router是不必要的,直接用a link 就好了。

这里看的是生成的url。

分布式爬虫的去重

https://zhangslob.github.io/2019/03/26/scrapy%E4%B8%8Escrapy-redis%E7%9A%84%E5%8E%BB%E9%87%8D/

当一套系统在发生分区故障后,客户端的任何请求都被卡死或者超时,但是,系统的每个节点总是会返回一致的数据,则这套系统就是 CP 系统,经典的比如 Zookeeper。

scrapy的是cp系统,针对获取数据来说,这里数据库主从等没有说。

图像 185

image-20220513152230296

vue 编译

vue 编译可以进行压缩,在页面处

添加vue.config.js

写如下代码

module.exports = {
    publicPath: process.env.NODE_ENV === 'production'
      ? '/dist/' // 打包后发布文件名
      : '/', // 开发环境相对路径
    devServer: {
        compress: true,
        disableHostCheck: true,
      },
  
  
}
  

然后ui页面打包。

部署时需要先安装serve

npm install serve -g

打包时候在dist文件夹下,就

serve -s dist

这个会生成URL便于访问了。

vue 需要安装cli,否则只有包

npm install -g @vue/cli

是否更新数据集

https://club.jd.com/comment/productPageComments.action?callback=&productId=3014239&score=0&sortType=5&page=2&pageSize=10&isShadowSku=0

京东有对应的评论爬虫内容。。

但是短暂的冲动之后,理智告诉我这样不好,对不起良心;而且一旦事泄,小兄弟搞不好要被退学,协查过来我的本硕学位搞不好也要没有了。

操作流程

先启动docker的mongodb

docker start mongo

再不用抓数据。

直接用

docker run --rm --network=host --name flask  xuan/flask:v01 /bin/bash -c "tail -f /dev/null"

flask 在 flask 的dockerfile 下,compose的没有写,因为cmd 没有动。

然后是vue@cli 这个似乎需要重新配置,因为写的时候在windows 下写的。

npm install -g @vue/cli

使用 vue ui 启动ui,然后到 任务项使用开发测试。