• 爬虫实战(一)—利用requests、mongo、redis代理池爬取英雄联盟opgg实时英雄数据


    概述

    可关注微信订阅号 loak 查看实际效果。

    代码已托管github,地址为:https://github.com/luozhengszj/LOLGokSpider 包括了项目的所有代码。

    此篇文章,主要记录利用Python request模块爬取LOL opgg英雄实时数据,并保存到mongodb中,爬取使用了可靠的redis维护IP代理池,这个过程已在腾讯云服务器上完成每日定时爬取,并完成个人订阅号 loak 的查询接口。

    • 以下简单写一下用到的技术,并在后面做详细的记录:

    爬虫相关:爬虫模块 requests、 mongodb模块 pymongo、 html解析 BeautifulSoup、 正则 re模块、 xml解析 xmltodict

    redis代理池:使用了Github IP代理池项目 jhao104/proxy_pool,在centos7完成redis安装、远程登录、密码登录等设置

    mongodb:完成在centos7上,Python2的完全卸载及Python3的安装,mongodb的安装、用户管理、远程登录、可视化管理adminMongo配置

    微信订阅号:完成微信订阅号 loak 的接口测试、腾讯云服务器用户消息接收、回复、保存

    centos7:完成定时任务实现、记录运行日志、多命令一次执行、根据进程名查询进程pid、及杀死进程

    • 程序的目录结构
      以下是程序的目录结构,LOLGokEnv 为虚拟环境、LOL是爬虫的主要实现包、SpiderUtil为爬虫过程中的工具包、Web为微信订阅号接口包。
    BaseException
    +-- LOLGokEnv
    +-- LOLGokSpider
     +-- Config.py
     +-- LOL
     |    +-- __init__.py
     |    +-- heroClass.py
     |    +-- mongoClient.py
     |    +-- opggSpider.py
     +-- SpiderUtil
     |    +-- __init__.py
     |    +-- hero_another_name.xml
     |    +-- wxUtil.py
     |    +-- xmlUtil.py
     +-- Web
     |    +-- __init__.py
     |    +-- wxWeb.py
    

    爬虫实现

    • 分析opgg网站信息、元素
      当确定爬取什么的时候,肯定首先看网站的构造、内容的元素,以及使用怎么的技术实现该网站的爬取。对于opgg网站,这个是实时的LOL官方英雄信息查询网站(版本比国服稍前)。
      打开网站 http://www.op.gg/champion/statistics 不难发现,其实爬取的有价值信息,大概就是英雄的强势度(T1、T2…)、胜率、登场率,以及英雄在对应位置上的胜率、登场率、出装、加点、天赋等信息。当然,为了实现数据的价值挖掘,还是要加上数据爬取的日期、版本等便于分析的字段。
      在这里插入图片描述
      在这里插入图片描述

    • 分析该网站的加载
      分析完网站的构造、元素组成够,大概可以看一下网站是怎么加载的了,也就是分析如何实现、以及使用何种技术更好的爬取。
      打开控制台,如下图所示,其实发现网站的加载十分简单,就是get请求一个简单的url,返回就是我们需要的界面:
      在这里插入图片描述
      至于英雄的详细界面,也是get请求一个有规则的url,如:http://www.op.gg/champion/neeko/statistics/mid .分别就是op.gg/champion/英雄/statistics/位置。

    • 实现网站的抓取、解析
      通过以上两步,接下来大概就可以编写代码了。使用BeautifulSoup进行解析,这个好像也没什么好说的,可以看之前的博文 Python爬虫(六)—解析利器 BeautifulSoup ,使用到了基本就是BeautifulSoup4的select、find、find_all函数。
      下面直接上一部分代码,timeout=120主要考虑到这个网站加载比较慢,不知道是不是IP限制的问题,当然以下代码还需加上异常处理、出错次数限制等,以保证爬虫不会中断。

        # 获取英雄列表
        herohtml = requests.get(opgg_config['OPGG_MAIN_URL'], headers=headers, timeout=120, proxy=proxy).text
        # 存储所有英雄的hero对象
        list_hero = []
        soup = BeautifulSoup(herohtml, 'lxml')
        hero_items = soup.find_all(class_='champion-index__champion-item')
        hero_item_version = soup.select_one('[class~=champion-index__version]').text.split(':')[1].strip()
    
        for hero_item in hero_items:
            hero_en_name = hero_item['data-champion-key']
            hero_cn_name = hero_item['data-champion-name']
            hero_positions_items = hero_item.find_all(class_='champion-index__champion-item__position')
            hero_positions = []
            for hero_position in hero_positions_items:
                hero_positions.append(hero_position.text)
            hero = HeroClass(hero_en_name, hero_cn_name, hero_positions, hero_item_version)
            list_hero.append(hero)
    

    redis维护IP代理池

    以下主要是在centos7下的安装、维护。

    • redis安装
      安装我是根据博客 https://blog.csdn.net/u010623954/article/details/80037078#commentBox 这个完成的,注意就是可以打开 http://download.redis.io/releases/ 选择比较新的版本进行下载安装。基本步骤概括以下就是:
      wget http://download.redis.io/releases/redis-5.0.4.tar.gz
      tar -zxvf redis-5.0.4.tar.gz -C /usr/local/
      gcc -v 如果没有gcc则下载:yum install -y gcc
      cd /usr/local/redis-5.0.4/
      make MALLOC=libc
      cd src && make install
      cd /usr/local/redis-5.0.4/src/
      ./redis-server
      出现redis的界面,就是安装成功了。

    • redis配置

      • 后台进程方式启动:
        修改/usr/local/redis-5.0.4/redis.conf: daemonize no 将值改为yes 保存退出
        指定redis.conf文件启动: ./redis-server /usr/local/redis-4.0.6/redis.conf
      • 设置redis远程连接:
        1.因为redis默认设置允许本地连接,所以我们要将redis.conf中将bind 127.0.0.1 改为bind 0.0.0.0或者注释该行;
        2.腾讯云服务器有一个安全组,找到并添加规则允许6379端口访问
      • 设置redis连接密码:
        在redis.conf中搜索requirepass这一行,然后在合适的位置添加配置:
        requirepass yourpassword
        设置完成后执行/usr/local/bin/redis-server /usr/local/redis-4.0.6/redis.conf 更新配置
      • 设置开机自启动
        通过 ps -ef | grep redis | grep -v grep | awk ‘{print $2}’ | xargs kill -9 将redis所有进程杀死。
        1、在/etc目录下新建redis目录: mkdir /etc/redis
        2、将/usr/local/redis-5.0.4/redis.conf 文件复制一份到/etc/redis目录下,并命名为6379.conf:
        cp /usr/local/redis-5.0.4/redis.conf /etc/redis/6379.conf
        3、将redis的启动脚本复制一份放到/etc/init.d目录下:
        cp /usr/local/redis-5.0.4/utils/redis_init_script /etc/init.d/redisd
        4、设置redis开机自启动,先切换到/etc/init.d目录下,然后执行自启命令chkconfig redisd on:
        如果显示service redisd does not support chkconfig 解决方法:使用vim编辑redisd文件,在第一行加入如下两行注释,保存退出:
        #chkconfig: 2345 90 10
        #description: Redis is a persistent key-value database
        注释的意思是,redis服务必须在运行级2,3,4,5下被启动或关闭,启动的优先级是90,关闭的优先级是10。
        再次执行开机自启命令chkconfig redisd on
        启动:service redisd start
        关闭:service redisd stop
    • redis远程连接
      我是使用RedisDesktopManager进行redis的可视化管理的,工具可以在github上直接下载安装。uglide/RedisDesktopManager https://github.com/uglide/RedisDesktopManager

    Python3、Mongodb、adminMongo

    • Python3安装
      这个主要是安装博客 https://www.cnblogs.com/johnny1024/p/8441396.html 完成的。主要步骤概括为以下:
      • 安装python3.6可能使用的依赖:
        yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel
      • 到python官网找到下载路径, 用wget下载
        wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tgz
      • 解压tgz包
        tar -zxvf Python-3.6.4.tgz
      • 把python移到/usr/local下面
        mv Python-3.6.4 /usr/local
      • 删除旧版本的python依赖
        ll /usr/bin | grep python
        rm -rf /usr/bin/python
      • 进入python目录
        cd /usr/local/Python-3.6.4/
      • 配置
        ./configure
      • 编译 make
        make
      • 编译,安装
        make install
      • 删除旧的软链接,创建新的软链接到最新的python
        rm -rf /usr/bin/python
        ln -s /usr/local/bin/python3.6 /usr/bin/python
        python -V
    • mongodb安装、卸载
      这个安装博文 https://www.cnblogs.com/hujiapeng/p/7008006.html 进行操作的,主要步骤是:
      • 配置yum管理包
        1、在路径/etc/yum.repos.d/下创建文件mongodb-org-3.4.repo
        cd /etc/yum.repos.d/
        touch mongodb-org-3.4.repo
        2、在文件mongodb-org-3.4.repo中写入如下内容
        [mongodb-org-3.4]
          name=MongoDB Repository
          baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
          gpgcheck=1
          enable=1
          gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
      • 安装mongodb
        yum install -y mongodb-org
        装mongodb-org包及其依赖包mongodb-org-server、mongodb-org-mongos、mongodb-org-shell、mongodb-org-tools
        数据库实例默认在/var/lib/mongo路径下,日志默认在/var/log/mongodb路径下,也可以通过修改/etc/mongod.conf文件的storage.dbPath和systemLog.path配置
      • 设置开机启动
        chkconfig mongod on
        service mongod start
        service mongod stop
      • 卸载
        service mongod stop
        yum erase $(rpm -qa | grep mongodb-org)
        rm -r /var/log/mongodb
        rm -r /var/log/mongodb
    • mongodb配置
      安装完成后,可以按照博文 https://www.jianshu.com/p/aadabfe3ee29 进行配置。
      • 远程连接配置
        修改配置文件mongodb.conf
        把 bind_ip=127.0.0.1 这一行注释掉或者是修改成 bind_ip=0.0.0.0
        /etc/init.d/mongodb restart
        远程连接
        mongo 134.567.345.23:27017/admin -uusername -p
      • 设置 admin

    进入控制台 :mongo
    创建管理员

         use admin
         db.createUser(
           {
             user: "myUserAdmin",
             pwd: "abc123",
             roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
           }
         )
    

    重启 MongoDB
    重启并进入控制台,强制使用用户名、密码认证。
    mongod --auth
    mongo
    授权
    use admin
    db.auth(“myUserAdmin”, “abc123” )
    添加数据库用户
    没添加用户之前,操作数据库会报错:

       > use test
       switched to db test
       > db.foo.insert( { x: 1, y: 1 } )
       WriteCommandError({
           "ok" : 0,
           "errmsg" : "too many users are authenticated",
           "code" : 13,
           "codeName" : "Unauthorized"
       })
    

    添加用户:

       use test
       db.createUser(
         {
           user: "myTester",
           pwd: "xyz123",
           roles: [ { role: "readWrite", db: "test" },
                    { role: "read", db: "reporting" } ]
         }
       )
    

    重新进入控制台,授权、执行插入操作:

          > use test
          switched to db test
          > db.auth("myTester", "xyz123" )
          1
          > db.foo.insert( { x: 1, y: 1 } )
          WriteResult({ "nInserted" : 1 })
    
    • adminMongo安装使用
      Github地址:mrvautin/adminMongo https://github.com/mrvautin/adminMongo
      安装参照博文 https://www.jianshu.com/p/6159fe96f53a
      安装adminMongo首先需要安装
      • node.js环境搭建
        • 下载地址:https://nodejs.org/en/download/
        • 安装完成后,打开cmd,输入 node -v,检查是否显示版本信息,如果显示即安装成功。
        • 打开cmd,输入npm -v校验npm工具是否安装成功,npm的作用就是对Node.js依赖的包进行管理,也可以理解为用来安装/卸载Node.js需要装的东西.
        • npm安装成功,在安装目录下新建node_cache,并使用cmd命令指定这个变量:

        npm config set cache “D:XXX”

      • adminMongo下载安装
        1、git下将adminMongo源码从github上clone下来:
        git clone https://github.com/mrvautin/adminMongo.git
        没有git请安装,第一次clone会报错:Permission denied (publickey). fatal: Could not read from remote repository.,解决办法参照博文:https://www.cnblogs.com/wmr95/p/7852832.html
        2、进入adminMongo路径:
        cd adminMongo
        npm install
        3、启动应用:
        npm start 或者 node app
        打开浏览器,输入http://127.0.0.1:1234就可以看到adminMongo的界面了!
      • MongoDB连接字符串
        可参照博文: https://www.cnblogs.com/imeiba/p/5702298.html
        在cmd连接使用:mongo 134.567.345.23:27017/admin -uusername -p
        adminMongo连接字符串为:mongodb://username:pssword@IP:prot/databasename

    微信订阅号接口测试与搭建

    • 微信公众平台的设置
      进入自己的订阅号,点击 基本设置 > 服务器配置 > 修改配置。设置如下图:
      在这里插入图片描述
      其中服务器地址(URL)两种写法:一种是写入域名/loak,一种是IP/loak,两者的区别是配置的中间件不一样:
      • 域名/loak 的Nginx的配置应为直接新增一个server,大概如下:
      server {  
              listen 80;  
              server_name wx.richule.com;
      
              # root需要写到python flask运行程序app.py的目录下
              root  /path/path/...;
      
              location / {
                  # 传到服务器的对应端口,假如你的python flask搭建的服务器后台运行在4000端口
                  proxy_pass http://127.0.0.1:4000;  # 转发到本地4000端口进行解析
              } 
              ......
              # 减少篇幅,这些就是随便配置就可以了
          } 
      
      • IP/loak 的Nginx的配置则是在解析端口(80或443)下增加 location,其中location 后面的也同样是python flask运行程序app.py的目录。
        服务器地址(URL)修改为:http://10.10.10.10/loak
        location增加一个:
            location /loak 
            {
                  proxy_pass http://127.0.0.1:4000;
            } 
        
    • 服务器的验证代码
      因为微信服务器发送到我们的服务器,格式是xml的如下:
          <xml>
          <ToUserName><![CDATA[gh_866835093fea]]></ToUserName>
          <FromUserName><![CDATA[ogdotwSc_MmEEsJs9-ABZ1QL_4r4]]></FromUserName>
          <CreateTime>1478317060</CreateTime>
          <MsgType><![CDATA[text]]></MsgType>
          <Content><![CDATA[你好]]></Content>
          <MsgId>6349323426230210995</MsgId>
          </xml>
      
      因此后台 Python flask代码则如下,其中:
    from flask import Flask,request
    import hashlib
    import xmltodict
    import time
    
    app = Flask(__name__)
    
    @app.route('/wx', methods=["GET", "POST"])
    def getinput():
        if (request.method == "GET"):
        # 表示是第一次接入微信服务器的验证,验证完之后可以删掉
            signature=request.args.get('signature')
            timestamp=request.args.get('timestamp')
            nonce=request.args.get('nonce')
            token = "maluguang"
            list = [token, timestamp, nonce]
            list.sort()
            sha1 = hashlib.sha1()
            sha1.update(list[0].encode('utf-8'))
            sha1.update(list[1].encode('utf-8'))
            sha1.update(list[2].encode('utf-8'))
            hashcode = sha1.hexdigest()
            echostr = request.args.get("echostr")
            if hashcode == signature:
                return echostr
            else:
                return ""
    
        elif request.method == "POST": # 这里是验证完后的接受处理用户发送的消息
            # 表示微信服务器转发消息过来
            xml_str = request.data
            if not xml_str:
                return""
            # 对xml字符串进行解析
            xml_dict = xmltodict.parse(xml_str)
            xml_dict = xml_dict.get("xml")
    
            # 提取消息类型
            msg_type = xml_dict.get("MsgType")
            if msg_type == "text":
            # 表示发送的是文本消息
            # 构造返回值,经由微信服务器回复给用户的消息内容
                resp_dict = {
                    "xml": {
                        "ToUserName": xml_dict.get("FromUserName"),
                        "FromUserName": xml_dict.get("ToUserName"),
                        "CreateTime": int(time.time()),
                        "MsgType": "text",
                        "Content": "you say:" + xml_dict.get("Content")
                    }
                }
    
                # 将字典转换为xml字符串
                resp_xml_str = xmltodict.unparse(resp_dict)
                # 返回消息数据给微信服务器
                return resp_xml_str
            else:
                resp_dict = {
                    "xml": {
                        "ToUserName": xml_dict.get("FromUserName"),
                        "FromUserName": xml_dict.get("ToUserName"),
                        "CreateTime": int(time.time()),
                        "MsgType": "text",
                        "Content": "Dear I Love you so much"
                    }
                }
                resp_xml_str = xmltodict.unparse(resp_dict)
                # 返回消息数据给微信服务器
                return resp_xml_str
    if __name__ == '__main__':
        app.run(port='4000')
      ```
    
    ## centos7一些shell脚本
    * shell脚本
    之前想编写一个shell,完成IP代理池运行进程的判断,在运行中则直接开始爬取,后来一直没成功,还请大神指教,到底应该怎么写,大概就是:
    ```javascript
    PIDS=`ps -ef |grep main.py |grep -v grep | awk '{print $2}'`
    if [ "$PIDS" != "" ]; then
      cd /home/LOLGokSpider/LOL && /home/LOLGokEnv/bin/python opggSpider.py > /home/cro_sh/spider.out 2>&1
    else
      cd /home/proxy_pool/ && proxy_pool_env/bin/python Run/main.py
      PIDS=`ps -ef |grep main.py |grep -v grep | awk '{print $2}'`
      if [ "$PIDS" != "" ]; then
      cd /home/LOLGokSpider/LOL && /home/LOLGokEnv/bin/python opggSpider.py
      else
      "error" > /home/cro_sh/proxy_pool_error.out 2>&1
      fi
    fi
    

    缩进语法这些应该是没问题的,就是他一直只运行到 cd /home/proxy_pool/ && proxy_pool_env/bin/python Run/main.py ,并没有开始爬取的进程。

    • 根据进程名查询、杀死

      ps -ef |grep main.py |grep -v grep
      ps -ef | grep 进程名 | grep -v grep | awk ‘{print $2}’ | xargs kill -9

    • 定时任务
      在这里插入图片描述

    loak订阅号效果

    输入:排行 上
    可以查询上单的强势英雄、胜率、登场率等
    输入:寒冰
    查询寒冰在各位置的占比、胜率、登场率
    输入:寒冰 ad
    查询寒冰在adc位置上的加点、出装、天赋等
    关于英雄的名称,可以输入别名,如下的瘟疫之源可以改成老鼠。
    在这里插入图片描述

    个人博客:Loak 正 - 关注人工智能及互联网的个人博客
    文章地址:爬虫实战(一)—利用requests、mongo、redis代理池爬取英雄联盟opgg实时英雄数据

  • 相关阅读:
    zBrow发布倒计时:对不起,让大家久等了
    《zBrow的资本论》
    zBrow智能浏览器
    zspt界面截图
    电商领域,唯一的“发明”级国家专利。
    zBrow界面截图截图
    zBrow多开界面截图
    网页滚动条样式
    关于margin参数解读
    JAVA的抽象类和抽象方法
  • 原文地址:https://www.cnblogs.com/l0zh/p/13739734.html
Copyright © 2020-2023  润新知