JavaScript脚本自动爬取网页下载文件,Ajax上传服务器

任务背景

paqu
寒假里,自己找了一份实习的工作,分配给我的任务是完成业务操作的自动化工作,就是提高老板的工作效率,解放双手。

老板的任务要求是:在阿里妈妈的订单下载页面中,由于有数据更新的时候,就要将订单报表,手动下载到电脑本地,然后用公司的开发工具上传到服务器中,这样就可以在平台中看到新生产的订单,这一过程比较的繁琐,而且一天要多次的操作,如何能够简单点,自动获取报表中的数据,然后自动的上传到服务器中去呢?这个就是我的一个任务了。

畅销助手公司

解决思路

由于是要给老板使用,于是在做技术选择的时候,就想应该使用方便的语言,不要让老板的电脑中添加太多的开发环境(Java,PHP,Python),并且主要是运行在网页中,所以很显然的是,我应该使用JavaScript,说实话,JavaScrpit这个脚本语言真是太强大了,前后端都进入了详情请看我的博文《Node.js的特点》)。

问题

说明了任务背景后,我总结了几个非常中要的问题:

1、在向网页中的一个请求发起的时候,用单独的JavaScript脚本是不在同一个域中的也就是说:你单独写一个javaScrpit代码,去请求别人服务器中的资源的时候,是没有权限的,平时我们下载资源是登入后,有权限进行下载文件,但是你写的代码中并没有进行登入,所以在自己写的代码中,你要么做登入的操作,要么在服务器中设置请求端允许跨域的操作,然而服务器是别人的,你怎么设置得了^_^(阿里妈妈服务器),做登入操作是在是比较的麻烦,而且是安全性的问题,所以最后决定是使用,登录状态后,执行脚本,再进行数据的请求。(什么是跨域, 跨域问题的解决,请看这里http://www.2cto.com/kf/201604/499381.html)

2、向服务器请求数据的时候,一开始是直接访问,请求后文件被下载在本地,但是如何再通过JavaScript再上传到服务其中,这个可是一个大的问题了,因为浏览器的规范中是:浏览器不能够直接操作硬盘的数据的,只有在用户手动提交文件(上传表单文件)才是可以获取的,如果可以的话,那不是黑客随意的通过浏览器端窃取你本地硬盘的数据了吗?(可是这样的事没有发生),所以请求的资源不能够下载在本地,应该保存在内存中,那么请求方式就要做一些变化,不能直接去跳转链接,而我这里做的就是用GET请求。

3、以什么样的方式,将数据上传到服务器中,由于实际的文件是一个excel文件,在最终的解决方案中,问题2中的方式获取的数据是二进制的流数据,如何让这个数据在后台成功获取呢?这个又是一个问题,因为是在脚本中写入代码。平时的我们提交表单数据的时候是通过键值对”Key”,”Value”的形式提交给后台的,后台通过的name值获取数据的,但是我们现在提交的是一个二进制文件数据,并且是在js脚本中,根本没有表单from,所以如何让它提交给后台呢?通过API的查询,我们最终使用的是Blob、FormData 来提交数据给后台。
所以综合上面的问题和解决方案,再来总结下任务:
1、使用JavaScript 爬取网页源码中的数据链接。
抓取网页中的连接

2、使用GET方式向阿里妈妈的服务器请求数据(跨域问题是难点)。
跨域问题的出现一般是这样的问题:

1
2
3
XMLHttpRequest cannot load http://myApiUrl/login. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.

3、将请求的数据先保存在内存中。

4、使用Blob、FormData将数据上传至服务器,向服务器发出处理请求。

最终方案实现

JavaScript代码的实现,这个脚本的代码

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
//获取网络中的jQuery
(function(func){
if( typeof $ == 'undefined' ){
var script = document.createElement('script'),
head = document.documentElement.firstChild;
script.src = 'http://m.youyouhd.com/static/library/jquery/2.1.4/jquery.min.js?v=1487321406';
script.onload = func;
head.insertBefore(script, head.firstChild);
}else{
$(func)
}
})(function(){
// 设置定时器,每隔一段时间,对数据进行获取,然后上传到服务器中
timeOut = setTimeout(function(){
var item = document.getElementsByTagName('a');
var urldown;
for (var i = 0; i < item.length; i++){
if (item[i].title=='下载报表') {
urldown = item[i].href;
break;
}
}
function createXHR(){
if(window.XMLHttpRequest){
return new XMLHttpRequest();
}else{
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
console.log("地址是:" + urldown);
// GET请求
var http = createXHR();
http.open('GET', urldown, true);
http.responseType = "blob";
http.send();
http.onreadystatechange = function(){
if (http.readyState == 4 && http.status== 200) {
console.info(http);
//创建 Blob对象、FormData对象
var xmlRoot = http.response;
var blod = new Blob([xmlRoot]);
var formData = new FormData();
formData.append('data', blod);
// 向服务器提交数据,
$.ajax({
url:
"http://laowang.zxmall.com/tbunion/create",
data:formData,
type:'POST',
processData:false,
contentType:false,
success:function(){
//提交成功后,向服务器触发 处理请求,直到全部数据处理为止。
var falg = true;
while(falg){
$.ajax({
async:false,
url:"http://laowang.zxmall.com/tbunion/import?ajax=1",
dataType: 'JSON',
success:function(rep){
console.log(rep);
//服务器向我发送剩余多少的数据
if (rep.left_count==0) {
falg = false;
}
}
})
}
},
error: function(){
console.log('ajax上传失败');
}
});
}
}
},300000);
})

后台的简单获取文件数据,使用PHP进行获取:

1
2
3
4
5
6
7
<?php
header("Access-Control-Allow-Origin: *");
if ($_FILES["data"]["error"] > 0){
echo "Return Code: " . $_FILES["data"]["error"] . "<br />";
}else{
move_uploaded_file($_FILES["data"]["tmp_name"], $_FILES["data"]["name"] . '.xls');
}

因为写的是脚本,并且是在浏览器中进行执行的,所以在浏览器中要进行触发设置,这段代码是直接以书签地址的方式,保存在浏览其中,要执行自动获取数据后,就打开响应的页面,点击该书签就行,相当于将JavaScript代码直接嵌入带当前的网页中,然后就可以解决跨域的问题了,(这个做法我很想知道是不是2016年中秋节 阿里员工用js写一个脚本强月饼的做法,我觉的很有可能是呀!),之前我也不知道有这样的做法,还是技术小黄同学给我提供的思路,整的是非常感谢了,下面的http地址是将上面的js代码引入,实际的地址是公司服务器的地址,这里做本地的测试,所以写的是本地的地址,如下:

1
javascript:(function(){ var script=document.createElement("script");script.setAttribute("src", "http://127.0.0.1:90/changxiao.js");document.getElementsByTagName("head")[0].appendChild(script); })

最后的结果是,完美的处理了数据,到目前为止没有出现什么的问题:
jieguo;

收获

shouhuo

在这次的短暂实习的过程中,感触真的是非常深刻,在这个团队中,感谢技术小黄对我的帮助,团队中能够有人给自己指导真的帮助是非常的大,对自己的成长非常的大,尤其是技术的提升很大。

在工作中,又深有体会了一遍:“在学校,课堂中学习的知识真的是非常的少,不足以完全解决工作中的问题,我们还要自身进行深入的学习”,这一深刻的道理呀!还有一点就是,在学习中的遇到的问题和在工作中遇到的问题,真不是一个等级,工作中遇到的问题,比如老大直接让你实现哪一个功能的话,这个问题可能是从来没有人做过的,需要自己去想解决思路,找到解决问题的办法,在学校中遇到的问题,那感觉实在是太简单了。同时,一些基本的技能真的是非常重要的,因为扎实的基础技能可以很高效的帮助你提高效率。还有非常重要的一点是:团队之间的交流很重要,交流能力对个人来讲是一个非常重要的能力,怎么让别人听懂你要说的,如何快速理解别人说的是什么,这是非常关键的,在团队中,交流是不可避免的。交流能力,领导力,这些或许是决定程序员未来道路方向的一个重要指标。

坚持原创技术分享,您的支持将鼓励我继续创作!