0%

JS代码理解

前言

在学习书本知识时遇到了不会的代码,身为一名热爱学习的有志青年肯定要认真学习搞明白(为了平时分!!!),顺便记录下这次的学习历程。

JS代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//定位区域
var area = page.match(/<tbody>[\s\S]*?<\/tbody>/g)[0];
area = area.replace(/\s/g, '');
//定位行
var row = [];
row = area ? area.match(/<tr[^>]*?>([\s\S]*?)<\/tr>/g) : area;
//取数据
var colu = [], fundName = [], fundCode = [];
//var date = {"secInfo": []};
//尝试把数据放到json里,输出失败,可忽略
for (var i = 0; i < row.length; i++) {
colu[i] = row[i].match(/<td[^>]*?>([\s\S]*?)<\/td>/g);
fundName[i] = colu[i] ? colu[i][0] : null;
fundCode[i] = colu[i] ? colu[i][1] : null;
fundName[i] = fundName[i] ? fundName[i].replace(/<td[^>]*?><a[^>]*?>/g, '').replace(/<\/a><\/td>/g, '') : fundName[i];
fundCode[i] = fundCode[i] ? fundCode[i].replace(/<td[^>]*?>/g, '').replace(/<\/td[^>]*?>/g, '') : fundCode[i];
//data.secInfo.push({"name": fundName[i], "code": fundCode[i]});
//尝试把数据放到json里,输出失败,可忽略
}

正则表达式

语法

/正则表达式主体/修饰符(可选)

修饰符

修饰符 描述
i 执行对大小写不敏感的匹配
g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)
m 执行多行匹配

表达式

表达式 描述
[abc] 查找方括号之间的任何字符
[0-9] 查找任何从 0 至 9 的数字
(x|y) 查找任何以 | 分隔的选项

元字符

元字符 描述
\d 查找数字
\s 查找空白字符
\b 匹配单词边界
\uxxxx 查找以十六进制 xxxx 规定的 Unicode 字符

量词

量词 描述
n+ 匹配任何包含至少一个 n 的字符串
n* 匹配任何包含零个或多个 n 的字符串
n? 匹配任何包含零个或一个 n 的字符串

python爬虫爬取数据

爬虫代码

此爬虫爬取的url与实验中的一致,爬取的网页即为JS代码中的page

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
import requests
import re

# 模拟kettle对基金数据进行抓取
class kettle:
def __init__(self):
self.url = 'http://www.yhfund.com.cn/main/qxjj/index.shtml'
self.session = requests.session()
self.headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36'
}
self.session.headers = self.headers

def getHtml(self):
self.html = self.session.get(url=self.url, verify=False).text

def save(self):
with open(r'./test.html', 'w') as fp :
fp.write(self.html)

def start(self):
self.getHtml()
self.save()
def main():
kt = kettle()
kt.start()

if __name__ == '__main__':
main()

爬取的部分数据展示

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
<tbody>

<!-- 1.非货币基金产品展示区start -->

<tr>

<th width="20%">基金<br>名称</th>

<th width="7%">基金<br>代码</th>

<th width="7%">更新<br>日期</th>

<th width="7%">单位<br>净值</th>

<th width="8%">累计<br>净值</th>

<th width="7%">最近<br>一周</th>

<th width="7%">最近<br>一月</th>

<th width="7%">最近<br>三月</th>

<th width="7%">最近<br>一年</th>

<th width="7%">今年<br>以来</th>

<th width="9%">成立以来<br>回报率</th>

<th width="8%">交易</th>

</tr>

<tr>

<td><a href="/main/qxjj/180001/fndFacts.shtml">银华优势企业混合</a></td>

<td>180001</td>

<td>11-01</td>

<td>1.7719</td>

<td>3.8327</td>

<!--最近一周-->

<td class="tsred">0.53%</td>

<!--最近一个月-->

<td class="tsred">4.82%</td>

<!--最近三个月-->

<td class="tsred">0.24%</td>

<!--最近一年-->

<td class="tsred">9.99%</td>

<!--今年以来-->

<td class="tsgreen">-0.01%</td>

<!--成立以来-->

<td class="tsred">760.68%</td>

<td><a class="btn_buy2" href="https://trade.yhfund.com.cn/yhxntrade/trade/buyPre.do?fundCode=180001" target="_blank">购买</a></td>

</tr>

<tr>

<td>
<a href="/main/qxjj/180003/fndFacts.shtml">银华-道琼斯88指数</a> </td>
......
</tr>
</tbody>

代码解析

Code 1

1
2
var area = page.match(/<tbody>[\s\S]*?<\/tbody>/g)[0];
area = area.replace(/\s/g, '');

此代码作用为定位区域,定位的区域为数据所在的区域,即为爬虫爬取的部分数据展示

page为爬取到的网页,在网页源码中利用正则表达式定位数据所在的代码块

  1. /<tbody><\/tbody>/:源代码中该区域以<tbody></tbody>为界限, \/ 此处作用是将 / 标记为原意字符,即匹配<tbody></tbody>

  2. [\s\S]*?:表示匹配任何包含零个或多个空白非空白字符的字符串,?表示非贪婪模式。以下举例说明?作用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 源代码
    <tbody>
    <tr>
    <td>数据</td>
    </tr>
    </tbody>
    <tbody>
    <tr>
    <td>数据</td>
    </tr>
    </tbody>
    1
    2
    3
    4
    // 加?后匹配代码
    <tr>
    <td>数据</td>
    </tr>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 不加?匹配代码
    <tr>
    <td>数据</td>
    </tr>
    </tbody>
    <tbody>
    <tr>
    <td>数据</td>
    </tr>
  3. g:执行全局匹配,查找所有匹配而非在找到第一个匹配后停止

  4. [0]:match[0]相当于match.group(0),获取匹配的第一组内容,即[\s\S]*?匹配的内容

  5. /\s/g:整个area匹配空白字符,替换为’’

Code 2

1
2
var row = [];
row = area ? area.match(/<tr[^>]*?>([\s\S]*?)<\/tr>/g) : area;

获取行数,即数据量,一行代表一条完整数据,在源代码中一对<tr></tr>代表一行完整的数据

  1. [^>]*?:非贪心的匹配任何包含零个或多个 非>的字符串,即匹配<tr xxx>,由于现在该网页的源代码已经看不出该正则的作用,我猜测在几年前该网页的源代码中可能有类似标签<tr bgcolor="#FF0000">

  2. ([\s\S]*?):非贪心的匹配零个或多个空白非空白字符,加括号的作用是可以将该括号内匹配的数据单独分配在一组,方便使用

  3. g:执行全局匹配,查找所有匹配而非在找到第一个匹配后停止

  4. 源代码中一对<tr></tr>代表一行数据,该正则表达式作用就是匹配所有的<tr>,即得到行数

Code 3

1
2
3
4
5
6
7
var colu = [], fundName = [], fundCode = [];
//var date = {"secInfo": []};
//尝试把数据放到json里,输出失败,可忽略
for (var i = 0; i < row.length; i++) {
colu[i] = row[i].match(/<td[^>]*?>([\s\S]*?)<\/td>/g);
fundName[i] = colu[i] ? colu[i][0] : null;
fundCode[i] = colu[i] ? colu[i][1] : null;

循环遍历行数,取出每一行数据的基金名称和基金代码

以下为一行完整数据

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
<tr>

<td><a href="/main/qxjj/180001/fndFacts.shtml">银华优势企业混合</a></td>

<td>180001</td>

<td>11-01</td>

<td>1.7719</td>

<td>3.8327</td>

<!--最近一周-->

<td class="tsred">0.53%</td>

<!--最近一个月-->

<td class="tsred">4.82%</td>

<!--最近三个月-->

<td class="tsred">0.24%</td>

<!--最近一年-->

<td class="tsred">9.99%</td>

<!--今年以来-->

<td class="tsgreen">-0.01%</td>

<!--成立以来-->

<td class="tsred">760.68%</td>

<td><a class="btn_buy2" href="https://trade.yhfund.com.cn/yhxntrade/trade/buyPre.do?fundCode=180001" target="_blank">购买</a></td>

</tr>

一行数据包含多个属性,即包含多列数据

一对<tr>标签,包含多个<td>标签

所以不难理解以下正则表达式的作用:匹配一行数据的所有属性

1
colu[i] = row[i].match(/<td[^>]*?>([\s\S]*?)<\/td>/g);
  1. [^>]*?:非贪心的匹配任何包含零个或多个 非>的字符串,即匹配<td xxx>,如源代码中的<td class="tsred">
  2. ([\s\S]*?):非贪心的匹配零个或多个空白非空白字符,加括号的作用是可以将该括号内匹配的数据单独分配在一组,方便使用
  3. g:执行全局匹配,查找所有匹配而非在找到第一个匹配后停止
1
2
3
4
5
6
7
// 此时colu[0]中的元素如下
colu[0] = [
<td><a href="/main/qxjj/180001/fndFacts.shtml">银华优势企业混合</a></td>,
<td>180001</td>,
<td>11-01</td>,
......
]

Code 4

1
2
fundName[i] = fundName[i] ? fundName[i].replace(/<td[^>]*?><a[^>]*?>/g, '').replace(/<\/a><\/td>/g, '') : fundName[i];
fundCode[i] = fundCode[i] ? fundCode[i].replace(/<td[^>]*?>/g, '').replace(/<\/td[^>]*?>/g, '') : fundCode[i];

通过colu[0]所展示的数据就不难得出最后四个正则表达式的作用

  1. <td xxx><a xxx>替换成’’
  2. </a></td>替换成’’,即可得到正确的名称
  3. <td xxx>替换成’’
  4. </td xxx>替换成’’,即可得到正确的代码

由于水平有限,以上就是对该JS代码的解析了