python爬取4399双人小游戏时间信息并分析

python爬取4399双人小游戏时间信息并分析


先列上在这个案例中我学到的正则表达式筛选标签内容的方法:

1
2
import re
re.sub(r'<[^>]+>', '', string)

说来惭愧,这是我第一次完全独立写爬虫,并将其与最近学习的数据分析库结合起来使用,我将其记录下来作日后参考与复习,也希望这个案例能帮助到同样需要练练手的同学。

Ps:不得不说4399的url看得我太难受了,新旧网页同时存在,也没个统一……本想爬取全站……但碍于页面跳转的问题,我放弃了原想法,转而选择了一个相对有规律的专题进行爬取

下面上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import requests
from bs4 import BeautifulSoup
from matplotlib import pyplot as plt
import re
import pandas as pd
from matplotlib import rc

# 设置plt生成图片显示中文
rc("font", family="MicroSoft YaHei", weight="bold", size="16")


# 获取网页html
def getHTMLText(url):
try:
kv = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
r = requests.get(url, headers=kv, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text

except Exception as e:
print(e)


# 填充存储游戏名和上传时间的字典
def fillGameBox(UrlList):
try:
# 创建空列表
name = []
date = []

# 传入Url列表
for url in UrlList:

# 获得每一个url的html文件
soup = BeautifulSoup(getHTMLText(url), "html.parser")

# 先粗略获取我们需要的li标签
for li in soup.findAll(attrs={"class": "tm_list"}):

# 再对标签内子标签等及其内容进行精处理
Name = li.select('b')

# 由于findall得到的内容是"<b>xxx</b>"的形式,我们用正则表达式筛选内容
for n in Name:
# 向空列表中装入我们的筛选结果
# 注意,re.sub()语法中最后元素必须为字符串,而n是列表元素,需进行转化
name.append(re.sub(r'<[^>]+>', '', n.string)) # 注意,re.sub()语法中最后元素必须为字符串,而n是列表元素,需进行转化
Date = li.select('em')

# <em>有重复标签,我们通过列表索引取出需要的时间列表
date_l = [Date[em * 2 + 1] for em in range(len(Date) // 2)] # <em>标签是两两出现的,所以长度必为偶数

# 正则表达式
for d in date_l:
# 空列表装载
date.append(re.sub(r'<[^>]+>', '', d.string))

# 创建一个字典,将我们的列表内容作values放入,并给出key,以传给DataFrame
result = {'name': name,
'date': date}
return result

except Exception as e:
print(e)


# 将字典转为DF文件并将数据按月聚合
def dfsort(result):
try:
df = pd.DataFrame(result)

# 将df['date']列转化为datetime类型,format需与date中表达方式一致
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')

# 因为原日期是按天计算,而我们需要得到统计结果,所以将其'date'改成了月份并设为index索引
df['date'] = [i.strftime('%Y-%m') for i in df['date']]
df.set_index('date', inplace=True)

# 按月份分组并统计
group = df.groupby('date').count()
return group

except Exception as e:
print(e)


# 由于4399的网页略凌乱……url名称层出不穷,我在这里只选择了双人小游戏分区来实现页面自动翻页功能
# 该函数返回一个含有了各页面url的列表
def getUrlList():
try:
UrlList = []

# 遍历分区内首页到末页
for i in range(1, 24):
if i == 1:
url = 'http://www.4399.com/special/old_1.htm'
else:
url = "http://www.4399.com/special/old_1_" + '%d' % i + ".htm"
UrlList.append(url)
return UrlList

except Exception as r:
print(r)


# 调用plt来展示数据统计结果,这里我选择了折线图,想看看游戏上传数目的随时间的变化
def show(group):
_x = group.index
_y = group.values
plt.figure(figsize=(20, 12), dpi=80)
plt.plot(_x, _y, label='当月游戏上传量')
plt.xticks(range(len(_x))[::5], list(_x)[::5], rotation=45)
plt.grid(alpha=0.7)
plt.xlabel('月份')
plt.ylabel('游戏数目')
plt.legend(loc='best')
plt.savefig('./01')
plt.show()


def main():
result = fillGameBox(getUrlList())
group = dfsort(result)
show(group)


main()

最后的结果是这样的

欢迎投喂,但你的支持就是对我最佳的回馈。