API其实很简单,记录下,主要是抓了没十几页..IP就被封了,下面还加上抓代理IP并自动切换的故事。
//获取齐云代理的数据
let cheerio = require('cheerio');
let axios = require('axios');
let getHtml = function(pageIndex){
let url = `http://www.qydaili.com/free/?action=china&page=${pageIndex}` ;
return axios.get(url)
.then(rs=>{return rs.data});
}
let getTable = function(html){
let $ = cheerio.load(html);
let $container = $('.container');
let $trs = $container.find('tbody tr');
let arr = [];
$trs.each((i,item)=>{
let ip = $(item).find('td[data-title="IP"]').text().replace('IP','');
let port = $(item).find('td[data-title="PORT"]').text().replace('PORT','');
let type = $(item).find('td[data-title="类型"]').text().replace('类型','');
arr.push({
ip : ip,
port : port,
type : type,
isHttps : type == 'HTTPS' ? true : false,
str : ip+':'+port
});
})
return arr;
}
module.exports = async function(pagesize){
let html = await getHtml(pagesize);
let arr = getTable(html);
return arr;
}
提供页码数,然后获得页面上的代理IP信息,返回即可,后续使用http 或 https 由客户端决定。
API 地址: https://www.haohaozhu.cn/f/y/api/Share/AllPhotoInPc
请求参数:
keyword : '',//关键词
page : page,//页数
time : +new Date()//请求时间
//好好住.. 抓图,为装修找灵感
let axios = require('axios');
let qs = require('querystring');
let fs = require('fs');
let async = require('async');
let url = 'https://www.haohaozhu.cn/f/y/api/Share/AllPhotoInPc';
let page = 1;
let map = {};
let ippool = [];//ip proxy pool
const tunnel = require('tunnel')
let getIpsFn = require('./getIps');
let currentIpsIndex = 0;
let getIps = async function(){
currentIpsIndex ++ ;
let arr =await getIpsFn(currentIpsIndex);
let httpsArr = [];
arr.forEach(item=>{
if(item.isHttps){
httpsArr.push(item);
}
})
if(httpsArr.length == 0){
httpsArr = await getIps();
}
console.table(httpsArr);
return httpsArr;
}
//cip : 是否切换IP
let getPicData = function(page,ipItem){
console.log(`当前使用的代理:${ipItem ? ipItem.str : '无'}`);
const tunnelProxy = ipItem ? tunnel.httpsOverHttp({
proxy: {
host: ipItem.ip,
port: ipItem.port,
},
}) : null;
return axios({
url : url,
method : 'post',
data : qs.stringify({
keyword : '',
page : page,
time : +new Date()
}),
proxy : false,
httpsAgent : tunnelProxy,
timeout : 10000,
headers : {
'accept': 'application/json, text/plain, */*',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en,zh-CN;q=0.9,zh;q=0.8',
'cache-control': 'no-cache',
// 'content-length': '25',
'content-type': 'application/x-www-form-urlencoded',
'origin': 'https://www.haohaozhu.cn',
'pragma': 'no-cache',
'referer': 'https://www.haohaozhu.cn/community/discover',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
})
.then(rs=>{
console.log(`获取到正常数据`)
// console.log(rs);
return rs.data;
})
.catch(err=>{
//如果报错,全部认为超时,换IP
console.log('这里的错误???')
console.log(err.message);
return {code : 2};
})
}
//抓取单个图片并进行保存
function fetchImg(item){
return new Promise((resolve,reject)=>{
if(!fs.existsSync('./'+item.folder+'/'+item.name)){
axios({
url : item.url,
method : 'get',
timeout : 5000,
responseType : 'stream',
onDownloadProgress : function(er){
console.log(er);
},
headers : {
'referer': 'https://www.haohaozhu.cn/community/discover',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
})
.then(rs=>{
console.log('抓取数据中...准备写入['+item.name+']')
let imgPath = './'+item.folder+'/'+item.name;
const ws = fs.createWriteStream(imgPath);
//当前图片写入完毕
var t = setTimeout(function(){
console.log(`超时未写入,删除文件...继续`)
fs.unlinkSync(imgPath);
resolve();
},15000);//
ws.on('close',()=>{
clearInterval(t);
resolve();
});
ws.on('error',(err)=>{
resolve();
})
rs.data.pipe(ws);
})
.catch(err=>{
console.log(err.message);
resolve();
})
}else{
console.log(`已经存在文件:${item.name}`);
resolve();
}
});
}
function waitFor(time){
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve();
},time);
});
}
//
;(async function start ( page,cip ){
try{
console.log(`启动抓取,当前页面:${page}`)
let data = await getPicData(page,cip);
if(null != data && undefined != data && data.data.rows.length == 0 && data.code == 1){
console.log(`已经没有数据可抓......-0---OVER`)
page = 1;
await start(page,cip);
}else if(null == data || undefined == data || null == data.data || undefined == data.data || data.code == 2){//IP proxy
//切换ip 代理池。
if(ippool.length == 0){
ippool = await getIps();
}
let ipItem = ippool.splice(0,1);
await start(page,ipItem[0]);
}else{
//json 存储起来
fs.writeFileSync('./json/'+page+'.json',JSON.stringify(data));
var rows = data.data.rows;
let imgList = [];
rows.forEach(item=>{
let photo = item.photo,
info = photo.photo_info,
tag = info.admin_tag,
list = info.image_list;
var imgArr = list.map(img=>{
return {
folder : 'img',
id : img.pic_id,
url : img.ori_pic_url,
name : tag+'_'+img.pic_id+'.png'
};
});
imgArr.push({
folder : 'avatar',
url : photo.user_info.big_avatar,
name : photo.user_info.uid+'.png'
});
imgList = imgList.concat(imgArr);
})
console.log(`当前页面共有图片:${imgList.length}张`)
//循环下载...
for(const item of imgList){
// let item = imgList[i];
if(item.id && map[item.id]){
console.log(`已存在该图片`)
}else{
await fetchImg(item);
}
}
console.log(` 当前页面抓取结束`)
//开始继续下一个,直接没有数据再进行结束
page++;
//等待10分钟后,继续执行
await start(page,cip);
}
}catch(e){
if(ippool.length == 0){
ippool = await getIps();
}
let ipItem = ippool.splice(0,1);
await start(page,ipItem[0]);
//有报错?不怕死。重新来
}
})(1);
伴随着数据后,主要是图片的存储,所以整体上来说,难度有点低。
代理使用了模块tunnel.
const tunnelProxy = ipItem ? tunnel.httpsOverHttp({
proxy: {
host: ipItem.ip,
port: ipItem.port,
},
}) : null;
axios({
url : url,
method : 'post',
proxy : false,
httpsAgent : tunnelProxy,
timeout : 10000
});
不知道是代理的问题还是代码的问题,总之,代码运行一段时间后...就卡那了,还没发现是哪里导致的,初步推测可能是好好住服务器给挂住请求了..
转载请注明出处: http://sdxlp.cn/article/技术.html