爬虫实战(一)—利用requests、mongo、redis代理池爬取英雄联盟opgg实时英雄数据
Posted on 2019-06-17 23:00 走过萧萧路 阅读(388) 评论(0) 编辑 收藏 举报概述
可关注微信订阅号 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
- 安装python3.6可能使用的依赖:
- 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
- 配置yum管理包
- 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
- node.js环境搭建
微信订阅号接口测试与搭建
- 微信公众平台的设置
进入自己的订阅号,点击 基本设置 > 服务器配置 > 修改配置。设置如下图:
其中服务器地址(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的如下:
因此后台 Python flask代码则如下,其中:<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>
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实时英雄数据