汽车之家批评

2019-07-16 20:05 关键词:汽车评论,汽车访谈 阅读:2095

2.7 汽车之家口碑爬虫
7 汽车之家口碑爬虫
需求分析
前端js反爬虫步伐分析
1成绩描述
2处理方法
爬虫框架
1 猎取全部车型的id
2本爬虫采取scrapy框架分析所需求的批评信息为
3将使用设置写入sttings中
结果展现
1.需求分析
因项目需求,要爬取汽车之家的口碑数据实行下一步分析。

但是普通的爬虫软件(如八爪鱼、火车头、神箭手)无法爬取批评(该公司采取了反爬虫步伐)。

经分析,发明该公司的的反爬虫措檀越如果用前端js去交换显现的字体,为一些标签。并且封住鼠标右键导致欠好观察源代码。

本文以处理各个成绩为递次。

2.1成绩描述
以随便率性车型(奥迪A4L)为例:

我们可以看到,表面上各个批评都由笔墨构成,但是翻开F12开辟者形式。我们就发明:一些描述词被交换成了span标签,如图:

他们的详细做法是:

公布的口碑注释中随机抽取某几个字使用span标签取代,标签内容位空,但css款式显现为所取代的文。

如此不会影响正使用户的浏览,只是在用鼠标挑选的时候是选不到被交换的笔墨的,对爬虫则会形成收罗内容不全的影响。

这些是用JS实现的,这是一段js代码:

(function(hZ_) {

functionEW_() { = DV_()[decodeURIComponent]('%E3%80%81%E3%80%82%E4%B8%80%E4%B8%8A%E4%B8%8B%E4%B8%8D%E4%BA%86%E4%BA%94%E5%92%8C%E5%9C%B0%E5%A4%9A%E5%A4%A7%E5%A5%BD%E5%B0%8F%E5%BE%88%E5%BE%97%E6%98%AF%E7%9A%84%E7%9D%80%E8%BF%9C%E9%95%BF%E9%AB%98%EF%BC%81%EF%BC%8C%EF%BC%9F' yc_());
= la_((yc_() 23; 3; 19; 17; 9; 1; 8; 12; 18; 13; 2; 4; 16; 5; 6; 21; 15; 11; 22; 14; 24; 0; 10; 7; 20), lf_(;));
= la_((10 _7, 6 _0; 2 _33, 14 _18; 8 _45, 8 _36; 0 _71, 16 _54; 13 _76, 3 _72; 0 _107, 16 _90; 15 _110, 1 _108; 4 _139, 12 _126; 9 _152, 7 _144; 10 _169, 6 _162; 4 _193, 12 _180; 11 _204, 5 _198; 3 _230, 13 _216; 1 _250, 15 _234; 13 _256, 3 _252; 6 _281, 10 _270; 9 _296, 7 _288; 13 _310, 3 _306; 6 _335, 10 _324; 7 _352, 9 _342; 6 _371, 10 _360; 5 _390, 11 _378; 5 _408, 11 _396; 7 _424, 9 _414; 6 _443, 10 _432lf_(;)), yc_(;));
Uj_();
return;;
}
function mS_() {
for (Gx_ = 0; Gx_ ; nf_.length; Gx_++) {
var su_ = Pn_(nf_[Gx_], ',');
var KN_ = '';
for (Bk_ = 0; Bk_ ; su_.length; Bk_++) {
KN_ += ui_(su_[Bk_]) + '';
}
Kx_(Gx_, KN_);
}
}
function NH_(Gx_) {
return '.hs_kw' + Gx_ + '_maindC';
}
function Ln_() {
return '::before { content:'
}
})(document);
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
他的逻辑是,预先界说好哪几个字要被交换,上面代码中的谁人很多%的字符串就是被交换的笔墨串,然后定义好每一个笔墨的序号,最终根据笔墨的序号对笔墨串实行从新排序并天生css款式,留意,最一开始的span标签的class属性中是有个序号的,这个序号就是用来定位应当对应哪个笔墨。

接下来要做的就是不过就是从js代码中找到这个笔墨串,找到笔墨串的递次,然后实行重排,然后根据span标签序号对原文
实行反向交换,从而获得完整的内容。

2.2处理方法:
从js代码中找到被交换的笔墨串温柔序

重排笔墨串

对原文中span标签根据class序号实行交换

实在2、3都对照简朴,重点是第一步,找到被交换的笔墨串温柔序,由于源代码中js代码是被混淆过的,无法间接看出哪个

是笔墨串,以是开始应当对js代码实行反混淆,这个反混淆也不是说非得完整的复原全部的js代码,实在只要能反混淆到能

让我们看出笔墨串温柔序是甚么就行了。

说一下反混淆的思绪,实在很简朴。就是施行起来对照贫苦罢了,混淆是利用将一个简朴的变量界说成庞杂的js代码的方法

实现的,但这类混淆体式格局实在是有限的(这个有限指的是混淆用的工具在天生混淆代码时肯定是工资预先界说好了几种形式

,工资界说的肯定是有限的,只要你把全部的形式找出来,便可以复原了)。举个例子

function iq_() {
'return iq_';
return '3';
}
1
2
3
4
这段代码实在你可以简朴的认为就是变量iq()即是’3’,使用正则婚配如此的代码形式,然后提取关键字:函数名和最终一个return的值,然后将提取到的信息保存起来用于对js代码实行全文交换。

function cz_() {
function _c() {
return 'cz_';
};
if (_c() == 'cz__') {
return _c();
} else {
return '84';
}
}
1
2
3
4
5
6
7
8
9
10
这段代码庞杂了一些,增加了判断,不过也简朴,利用正则婚配如此的形式,然后提取关键字:函数名、第一个return的值,判断中==前面的值,最终一个return的值,然后本身实行判断来肯定cz_()的值应当是多少,保存起来实行全文交换。

以此类推,每种形式都可使用正则来提取关键字并实行全文交换来反混淆,最后我们会获得一个大概被复原的js代码,当中的笔墨串温柔序都清晰可见,再使用正则婚配出来便可以了。

需求留意的一点是偶然候被交换的不是单个笔墨,而是一些词语,这是找到的递次是”3,1;23,5”如此的,不过这些小伎俩应当不算甚么,很好处理。

上面给出完整的代码:

# coding:utf8
import re
import urllib
import
import requests


def get_char(js):
all_var = {}
# 判断混淆 无参数 返回常量 函数
if_else_no_args_return_constant_function_functions = []
"""
function zX_() {
function _z() {
return '09';
};
if (_z() == '09,') {
return 'zX_';
} else {
return _z();
}
}
"""
constant_function_regex4 = """
function\s+\w+\(\)\s*\{\s*
function\s+\w+\(\)\s*\{\s*
return\s+[\'\"][^\'\"]+[\'\"];\s*
\};\s*
if\s*\(\w+\(\)\s*==\s*[\'\"][^\'\"]+[\'\"]\)\s*\{\s*
return\s*[\'\"][^\'\"]+[\'\"];\s*
\}\s*else\s*\{\s*
return\s*\w+\(\);\s*
\}\s*
\}
""",
re.X)
l = constant_function_
# print("l 38",l)
for i in l:
function_name = """
function\s+(\w+)\(\)\s*\{\s*
function\s+\w+\(\)\s*\{\s*
return\s+[\'\"]([^\'\"]+)[\'\"];\s*
\};\s*
if\s*\(\w+\(\)\s*==\s*[\'\"]([^\'\"]+)[\'\"]\)\s*\{\s*
return\s*[\'\"]([^\'\"]+)[\'\"];\s*
\}\s*else\s*\{\s*
return\s*\w+\(\);\s*
\}\s*
\}
""", i,
re.X)
if_else_no_args_return_constant_function_
js = "")
# 交换全文
a, b, c, d = function_
all_var["%s()" % a] = d if b == c else b

# 判断混淆 无参数 返回函数 常量
if_else_no_args_return_function_constant_functions = []
"""
function wu_() {
function _w() {
return 'wu_';
};
if (_w() == 'wu__') {
return _w();
} else {
return '5%';
}
}
"""
constant_function_regex5 = """
function\s+\w+\(\)\s*\{\s*
function\s+\w+\(\)\s*\{\s*
return\s+[\'\"][^\'\"]+[\'\"];\s*
\};\s*
if\s*\(\w+\(\)\s*==\s*[\'\"][^\'\"]+[\'\"]\)\s*\{\s*
return\s*\w+\(\);\s*
\}\s*else\s*\{\s*
return\s*[\'\"][^\'\"]+[\'\"];\s*
\}\s*
\}
""",
re.X)
l = constant_function_
# print("l 87",l)
for i in l:
function_name = """
function\s+(\w+)\(\)\s*\{\s*
function\s+\w+\(\)\s*\{\s*
return\s+[\'\"]([^\'\"]+)[\'\"];\s*
\};\s*
if\s*\(\w+\(\)\s*==\s*[\'\"]([^\'\"]+)[\'\"]\)\s*\{\s*
return\s*\w+\(\);\s*
\}\s*else\s*\{\s*
return\s*[\'\"]([^\'\"]+)[\'\"];\s*
\}\s*
\}
""", i,
re.X)
if_else_no_args_return_function_constant_
js = "")
# 交换全文
a, b, c, d = function_
all_var["%s()" % a] = b if b == c else d

# var 参数即是返回值函数
var_args_equal_value_functions = []
"""
var ZA_ = function(ZA__) {
'return ZA_';
return ZA__;
};
"""
constant_function_regex1 =
"var\s+[^=]+=\s*function\(\w+\)\{\s*[\'\"]return\s*\w+\s*[\'\"];\s*return\s+\w+;\s*\};")
l = constant_function_
# print("l 119",l)
for i in l:
function_name = "var\s+([^=]+)", i).group(1)
var_args_equal_value_
js = "")
# 交换全文
a = function_name
js = re.sub("%s\(([^\)]+)\)" % a, r"\1", js)

# var 无参数 返回常量 函数
var_no_args_return_constant_functions = []
"""
var Qh_ = function() {
'return Qh_';
return ';';
};
"""
constant_function_regex2 = """
var\s+[^=]+=\s*function\(\)\{\s*
[\'\"]return\s*\w+\s*[\'\"];\s*
return\s+[\'\"][^\'\"]+[\'\"];\s*
\};
""",
re.X)
l = constant_function_
# print("l 144",l)
for i in l:
function_name = """
var\s+([^=]+)=\s*function\(\)\{\s*
[\'\"]return\s*\w+\s*[\'\"];\s*
return\s+[\'\"]([^\'\"]+)[\'\"];\s*
\};
""",
i,
re.X)
var_no_args_return_constant_
js = "")
# 交换全文
a, b = function_
all_var["%s()" % a] = b

# 无参数 返回常量 函数
no_args_return_constant_functions = []
"""
function ZP_() {
'return ZP_';
return 'E';
}
"""
constant_function_regex3 = """
function\s*\w+\(\)\s*\{\s*
[\'\"]return\s*[^\'\"]+[\'\"];\s*
return\s*[\'\"][^\'\"]+[\'\"];\s*
\}\s*
""",
re.X)
l = constant_function_
# print("l 176",l)
for i in l:
function_name = """
function\s*(\w+)\(\)\s*\{\s*
[\'\"]return\s*[^\'\"]+[\'\"];\s*
return\s*[\'\"]([^\'\"]+)[\'\"];\s*
\}\s*
""",
i,
re.X)
no_args_return_constant_
js = "")
# 交换全文
a, b = function_
all_var["%s()" % a] = b

# 无参数 返回常量 函数 中央无混淆代码
no_args_return_constant_sample_functions = []
"""
function do_() {
return '';
}
"""
constant_function_regex3 = """
function\s*\w+\(\)\s*\{\s*
return\s*[\'\"][^\'\"]*[\'\"];\s*
\}\s*
""",
re.X)
l = constant_function_
# print("l 206",l)
for i in l:
function_name = """
function\s*(\w+)\(\)\s*\{\s*
return\s*[\'\"]([^\'\"]*)[\'\"];\s*
\}\s*
""",
i,
re.X)
no_args_return_constant_sample_
js = "")
# 交换全文
a, b = function_
all_var["%s()" % a] = b

# 字符串拼接时使无参常量函数
"""
(function() {
'return sZ_';
return '1'
})()
"""
constant_function_regex6 = """
\(function\(\)\s*\{\s*
[\'\"]return[^\'\"]+[\'\"];\s*
return\s*[\'\"][^\'\"]*[\'\"];?
\}\)\(\)
""",
re.X)
l = constant_function_
# print("l 236",l)
for i in l:
function_name = """
\(function\(\)\s*\{\s*
[\'\"]return[^\'\"]+[\'\"];\s*
return\s*([\'\"][^\'\"]*[\'\"]);?
\}\)\(\)
""",
i,
re.X)
js = function_

# 字符串拼接时使用返回参数的函数
"""
(function(iU__) {
'return iU_';
return iU__;
})('9F')
"""
constant_function_regex6 = """
\(function\(\w+\)\s*\{\s*
[\'\"]return[^\'\"]+[\'\"];\s*
return\s*\w+;
\}\)\([\'\"][^\'\"]*[\'\"]\)
""",
re.X)

l = constant_function_
# print("l 264",l)
for i in l:
function_name = """
\(function\(\w+\)\s*\{\s*
[\'\"]return[^\'\"]+[\'\"];\s*
return\s*\w+;
\}\)\(([\'\"][^\'\"]*[\'\"])\)
""",
i,
re.X)
js = function_
print("275",js)
# 猎取全部变量
var_regex = "var\s+(\w+)=(.*?);\s"
var_find = js)
print("var_find",var_find)
for var_name, var_value in var_find:
var_value = var_"\'\"").strip()
# print(var_name,"---",var_value)
if "(" in var_value:
var_value = ";"
all_var[var_name] = var_value
print("all var",all_var)
# 注释掉 此正则大概会把关键js语句删撤除
# js = "", js)

for var_name, var_value in all_
js = var_value)
print("----282",js)
js = re.sub("[\s+']", "", js)
print("----284",js)
string_m = "(%\w\w(?:%\w\w)+)", js)
# string = "utf-8").decode("utf8")
print("string_m",string_
string = "utf-8").decode("utf8")
print(string)
index_m = "([\d,]+(;[\d,]+)+)", js[string_
print(index_
string_list = list(string)
print("str",len(string_list))
# print("string_list",string_list)
index_list = index_";")
# print("index_list",index_list)
_word_list = []
# print(type(_word_list))
# print(_word_list)
i = 1
exflag = 0;
# deal exception

# print("--max ",type(int(max(index_list))))
max_index=0;
for word_index_list in index_list:
_word = ""
if "," in word_index_list:
word_index_list = word_index_",")
word_index_list = [int(x) for x in word_index_list]
else:
word_index_list = [int(word_index_list)]
for word_index in word_index_list:
# print(word_index)
if(word_index;max_index):
max_index=word_index
try:
string_list[word_index]
except Exception as e:
exflag=1;
print(max_index)
print("exflag",exflag)
less = max_index - len(string_list)
print(less)
for word_index_list in index_list:
_word = ""
if "," in word_index_list:
word_index_list = word_index_",")
# print("word_index_list",word_index_list)
word_index_list = [int(x) for x in word_index_list]
# print("word_index_list", word_index_list)
else:
word_index_list = [int(word_index_list)]
j = 1;
for word_index in word_index_list:
# print("for",j)
j += 1
# print("word_index",word_index)
# print("string_list[word_index]",string_list[word_index])
try:
_word += string_list[word_index-1-less]
except Exception as e:
print(e)

# print(_word)
_word_
# print("----------")
# print(i)
# print(_word_list)

i += 1

return _word_list


def get_complete_text_autohome(text):
#print("text0",text)
text = "\u0027","'").replace(r"\u003e",";").replace(r"\u003c",";")
#print("text1",text)
js = ";!--@HS_ZY@--;;script;([\s\S]+)\(document\);;/script;", text)
#print("find : %s" %
if not js:
print(" if not js:")
return text
try:
#print("try0")
char_list = get_char(
print("try111")

except Exception as e:
print(e)
print("except222")
return text

def char_replace(m):
index = int(m.group(1))
char = char_list[index]
return char

text = ";span\s*class=[\'\"]hs_kw(\d+)_[^\'\"]+[\'\"];;/span;", char_replace, text)
# print(text)
return text


# resp = "")
resp = "")
= "gbk"
text = get_complete_text_autohome(


print(";!--@HS_BASE64@--;.*;!--@HS_ZY@--;", text).group())
print("2")
# print(";div\s*class=[\'\"]text-con[^\'\"]*?[\'\"];([\s\S]+?);/div;", text).group(1))
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
前一个函数是焦点,用于剖析js

3.爬虫框架
3.1 猎取全部车型的id
开始利用爬虫软件爬取了 汽车列表 内里的全部汽车id
,用两层轮回爬取所有页面的批评:

# 两层遍历,分别遍历车型和页数
for i in car_id_list: # i代表从车型的遍历
for j in range(1,101): # j代表批评页数,range(1,3)示意1到2页
req = ""+str(i)+"/index_"+str(j)+".html#dataList")

return reqs
1
2
3
4
5
6
3.2本爬虫采取scrapy框架,分析所需求的批评信息为:
# 车ID
CAR_ID =
# 车名
CAR_NAME =

# 用户ID
USER_ID =
# 用户名
USER_NAME =

# 购置地点
PURCHASE_PLACE =
# 购置时候
PURCHASE_TIME =
# 裸车购置价
CAR_PRICE =
# 购车目标
PURCHASE_PURPOSE =

# 评分- 空间
SCORE_SPACE =
# 评分- 动力
SCORE_POWER =
# 评分- 操控
SCORE_CONTROL =
# 评分- 油耗
SCORE_FUEL_CONSUMPTION =
# 评分- 温馨性
SCORE_COMFORT =
# 评分- 表面
SCORE_EXTERIOR =
# 评分- 内饰
SCORE_INTERIOR =
# 评分- 性价比
SCORE_COST_EFFECTIVE =

# 批评的url
COMMENT_URL =
# 批评的内容
COMMENT_CONTENT =

# 有多少人支持这条口碑
COMMENT_SUPPORT_QUANTITY =
# 有多少人看过这条口碑
COMMENT_SEEN_QUANTITY =
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
将其写进item中。

3.3将使用设置写入sttings中
# 绕过
ROBOTSTXT_OBEY = False

#纪录日记
LOG_FILE = "scrapy_autohome_"

# 保存文件编码范例
FEED_EXPORT_ENCODING = 'GBK'

# 假装chrome
USER_AGENT = 'Mozilla/5.0 (Windows NT Win64; x64) AppleWebKit/ (KHTML, like Gecko) Chrome/ Safari/
1
2
3
4
5
6
7
8
9
10
11
12
如此利用我们前面学习的scrapy框架的常识,再加上破解的js。我们胜利爬取了汽车之家的数据。经过实验爬取了 快要22万条批评。

4.结果展现
1.数据条数:

2.数据花样

联系邮箱:1390477380@qq.com 客服QQ:1390477380

2002-2019 Copyright © 汽车群 版权所有