英雄联盟峡谷之巅前100爬取(动态网页+json格式解析)

目的是爬取英雄联盟官网的峡谷之巅前100的信息,经观察发现,每一页只有25个玩家的信息。

先看网页源代码
在这里插入图片描述
看到前面,结构清晰,很好抓取。

到了中间部分发现只有前25个,后面的数据貌似被隐藏了。在此处可见,在翻页时加载了json文件
在这里插入图片描述
于是就去抓包找json文件。。
当翻页时,网站的url并没有改变,翻看前4页,通过抓包发现一共加载了3个json文件
在这里插入图片描述
通过对比network下的3个json文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
首先是Query string就是以get方式的请求,这里的Query string就是在url尾部加上了一些索引的参数。观察发现Page是规律的变化的,而rid是无规律的变化。那么就来尝试一下删掉rid进行索引的结果是怎样的

复制General下的Request URL
在这里插入图片描述
在新的网页加载一哈,尝试删掉一些参数,得到了json格式的数据
在这里插入图片描述
也就是说变成了解析json文件就可以获取网页的信息了。

思考:动态网页的基础也是像静态网页一样去提取数据,动态网页只是url变得没有那么明显,需要自己去抓包找规律,还有多了解析json数据罢了。

解析json数据
首先可以知道json是一种存储格式,是由[]和{}组成的,一个用xml文件也可以用josn表示出来,所以解析方法不就和解析html的时候差不多嘛,会Xpath,这个就类比完事,而且比Xpath还爽。。Xpath的提取思想是“找到循环的节点,然后分别写大循环和小循环”,json也类比此。但是在此之前要先把前面的“var J_TopCanyonRank = ”去掉,因为要把json解析成python对象再处理的话,只能是正确的json格式,也就是只有{}和[]。这里可以把json数据复制一下,去www.json.cn去解析一下会看得很清晰。
在这里插入图片描述
先来测试一下json分析的代码吧。。

import urllib.request
import urllib.parse
import requests
import jsonpath
import json
import re

''' 
注意此处的关键之处在于,前面的var J_TopCanyonRank = 这个东西要除掉
json不可解析出这个东,所以细节1,先用正则表达式把{}的部分匹配出来
为何要这样想?因为json就只有{}和[]组成。而且网上找半天没找到解决方法
'''

url = 'http://apps.game.qq.com/lol/a20150928lolRF/TopCanyonRank.php?module=UserRankList&e_num=25&Page=3'
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0"
    }


# 1.使用urllib
# request = urllib.request.Request(url, headers=headers)
# response = urllib.request.urlopen(request)
# html = response.read()
# json_data = json.loads(html,strict=False)
# list = jsonpath(json_data, "$..name")
# for i in list:
#     print(i)


# 2.使用requests
response = requests.get(url, headers=headers)
string = re.findall('var J_TopCanyonRank = (.*)', response.text, re.S)
if string:
 	print(string)

# result = json.loads(string)这样会报错
# TypeError: the JSON object must be str, bytes or bytearray, not 'list'
# 解决方法:result = json.loads(string[0]) 把string改成string[0]就好了
result = json.loads(string[0])
print(result)

# 根据Xpath的思想"找循环的节点,然后分别找大循环和小循环"写出次循环
# objects = result["UserRankList"]["list"]
#最好使用get()方法,因为如果键不存在会返回None而不是报错
objects = result.get("UserRankList").get("list")
for obj in objects:
    name = obj.get("name")
    print(name)

注意事项

首先是网页上的信息
在这里插入图片描述
1.有个不安全,为防止SSL错误,在get参数里加上verify = False
2.注意编码格式是gbk
3.注意 用re 除掉前面的“var J_TopCanyonRank = ”这个字符串

上马!

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2019-01-28 12:44:09
# @Author  : (1412852608@qq.com)
# @Link    : https://me.csdn.net/qq_43391383
# @Version : $Id$

import requests
import urllib.request
# from requests.exceptions import RequestException
# from fake_useragent import UserAgent
from lxml import etree
from multiprocessing import Pool
import json
import re
import pymongo
import time

#连接数据库
client = pymongo.MongoClient('localhost', 27017)
mydb = client['mydb']
league_of_legend = mydb['league_of_legend']

headers = {
    "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Referer': 'http://lol.qq.com/act/a20170704super/ranking.shtml',
}


# def get_response(url):
#     try:
#         response = requests.get(url, headers=headers, verify=False)
#         if response.status_code == 200:
#             return response.text
#         return None
#     except RequestException:
#         return None


def get_html_data(url):  # 前25页是xml格式,等我写完以后我才发现其实全部内容都可以用json提取
    request = urllib.request.Request(url, headers=headers)
    response = urllib.request.urlopen(request)
    selector = etree.HTML(response.read().decode('gbk'))
    bigCircle = selector.xpath('//tbody/tr')
    for section in bigCircle:
        rank = section.xpath('td[1]/text()')
        if not rank:
            continue
        else:
            rank = rank[0]
        name = section.xpath('td[2]/a[2]/text()')[0]
        grade = section.xpath('td[3]/text()')[0]
        point = section.xpath('td[4]/text()')[0]
        rate = section.xpath('td[5]/text()')[0]
        data = {
            'rank': rank,
            'name': name,
            'grade': grade,
            'point': point,
            'rate': rate,
        }
        print('正在爬取第%s名玩家...' % rank)
        league_of_legend.insert_one(data)
        print('第{0}名玩家爬取完成'.format(rank))


def get_json_data(url):
    json_content = requests.get(url, headers=headers, verify=False)#防ssl error
    string = re.findall('var J_TopCanyonRank = (.*)', json_content.text, re.S)
    result = json.loads(string[0])
    # objects = result["UserRankList"]["list"]
    # for obj in objects:
    #     name = obj["name"]
    # 最好使用.get()方法,因为.get()如果键不存在不会报错而是返回None
    objects = result.get("UserRankList").get("list")
    for obj in objects:
        rank = obj.get("iRank")
        name = obj.get("name")
        grade = obj.get("tier")
        if grade == 30:  # 经过观察json数据发现,30是最强王者,31是宗师。还有注意此处不用eval()
            grade = '最强王者'
        else:
            grade = '傲视宗师'
        point = obj.get("league_points")
        total_wins = obj.get("total_wins")  # json里面没给胜率,只能根据json里的胜场和负场进行计算
        total_losses = obj.get("total_losses")
        total = eval(total_wins) / (eval(total_wins) + eval(total_losses))
        rate = str(int(total * 100)) + '%'
        data = {
            'rank': rank,
            'name': name,
            'grade': grade,
            'point': point,
            'rate': rate,
        }
        print('正在爬取第%s名玩家...' % rank)
        league_of_legend.insert_one(data)
        print('第{0}名玩家爬取完成'.format(rank))


if __name__ == '__main__':
    start_time = time.time()
    # pool = Pool(processes = 2)
    first_url = 'http://lol.qq.com/act/a20170704super/ranking.shtml'
    # pool.map(get_html_data,first_url)
    get_html_data(first_url)
    time.sleep(2)
    second_urls = [
        'http://apps.game.qq.com/lol/a20150928lolRF/TopCanyonRank.php?module=UserRankList&e_num=25&Page={0}'.format(str(i)) for i in range(2, 5)]
    for second_url in second_urls:
        # pool.map(get_json_data,second_url)
        get_json_data(second_url)
        time.sleep(1)
    end_time = time.time()
    timeout = end_time - start_time
    print("时间就是金钱,你看这程序花了{}秒".format(timeout))
    

Result!
在这里插入图片描述
其实在分析这个的过程中遇到了很多困难。但是没有什么是看视频,看博客,看书解决不了的。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值