Предыстория: Женские голоса участвовали в коротком тренировочном лагере по письму и служили наблюдателями за небольшим классом.Каждые выходные им нужно было подсчитать, сколько статей написал каждый студент и какие статьи они написали за последнюю неделю. Дабы осчастливить женские голоса, я пообещал написать ей коротенький краулер для статистических данных.Ведь я в этом деле.Если это можно решить программой, то я точно не буду заниматься таким повтором физическая работа.
Далее давайте вместе введем написание этого гада
1. Предварительный анализ:
Сначала разберем, как мы хотим подняться, как показано на рисунке:
первый шаг:
Нам нужно зайти в пользовательский центр каждого студента по этой ссылке:Краткое описание.com/U/Hungry 221 удобно 7…
Это можно сделать только с помощью женского билета, чтобы помочь нам собрать ссылку на пользовательский центр каждого ученика в его классе. С такой ссылкой на пользовательский центр первым шагом, который нам нужно просканировать, является этот пользовательский центр.
Шаг 2:
Чтобы просканировать пользовательский центр, нам нужно получить некоторые данные. Например: мы считаем данные за предыдущую неделю, поэтому нам нужна коллекция ссылок и имен пользователей для деталей статьи за определенный период времени.
Как получают эти данные? Как показано выше: чтобы получить имя пользователя, нам нужно$('.nickname')Текста здесь достаточно. Чтобы получить ссылку на детали статьи за определенный период времени, нам нужно пройти$('.note-list li')середина$('.time')а также$('.titile')
третий шаг:
Просканируйте ссылку со сведениями о статье, полученную на втором этапе, и просканируйте содержимое в сведениях о статье. Ссылки, похожие на сведения о статье:woo woo Краткое описание.com/fear/ah ah ah 1 отправить 2 ах 0…
На странице сведений о статье получаем необходимые нам данные, такие как: заголовок, количество слов, количество прочитанного и т. д. Как показано ниже
четвертый шаг:
Сгенерируйте лист excel из полученных данных, чтобы женские голоса боготворили вас больше, вау, Шри-Ланка одна из них.
2. Предварительная подготовка:
Часто приведенный выше анализ, давайте подготовим инструменты, необходимые краулеру:
-
cheerio: позволяет вам управлять просканированной страницей, как с помощью jquery -
superagent-charset: Решить проблему кодирования страницы, которая уползла назад -
superagent: используется для инициации запроса -
async: для асинхронных процессов и управления параллелизмом -
ejsexcel: используется для создания листа Excel -
express,node >=6.0.0Конкретное использование этих модулей можно найти здесь,www.npmjs.com, некоторые варианты использования будут упомянуты ниже
3. Начните сканирование
1. Мы поместили ссылку на пользовательский центр Цзяньшу всех студентов в файл конфигурации config.js и определили путь хранения сгенерированного листа Excel:
const path = require('path');
module.exports = {
excelFile: {
path: path.join(__dirname, 'public/excel/')
},
data: [
{name:"糕小糕",url:"http://www.jianshu.com/u/eeb221fb7dac"},
]
}
Поскольку вы хотите защитить информацию других людей, вы можете пойти в Цзяньшу, чтобы найти пользовательские центры других людей и создать больше данных.
2. Сначала мы определяем некоторые глобальные переменные, такие как: базовые ссылки, текущий параллелизм и получение неправильного набора ссылок.
let _baseUrl = "http://www.jianshu.com",
_currentCount = 0,
_errorUrls = [];
3. Инкапсулируйте некоторые функции:
// 封装 superagent 函数
const fetchUrl = (url,callback) => {
let fetchStart = new Date().getTime();
superagent
.get(url)
.charset('utf-8')
.end((err, ssres) => {
if(err) {
_errorUrls.push(url);
console.log('抓取【'+ url +'】出错');
return false;
}
let spendTime = new Date().getTime() - fetchStart;
console.log('抓取:'+ url +'成功,耗时:'+ spendTime +'毫秒,现在并发数为:'+ _currentCount );
_currentCount--;
callback(ssres.text);
});
}
// 数组去重
const removeSame = (arr) => {
const newArr = [];
const obj = {};
arr.forEach((item) => {
if(!obj[item.title]) {
newArr.push(item);
obj[item.title] = item.title;
}
});
return newArr;
}
4. Начните сканировать пользовательский центр и получите ссылку на детали статьи за определенный период времени.
// 爬取用户中心,获取某个时间段文章详情链接
const crawlUserCenter = (res,startTime,endTime) => { //startTime,endTime来自于用户的ajax请求时间
const centerUrlArr = config.data;
async.mapLimit(centerUrlArr, 5, (elem, callback) => {
_currentCount++;
fetchUrl(elem.url, (html) => {
const $ = cheerio.load(html);
const detailUrlArr = getDetailUrlCollections($,startTime,endTime);
callback(null,detailUrlArr); //callback是必须的
});
}, (err, detailUrlArr) => { // 并发结束后的结果 ,需要由 [[abc,def],[hij,xxx]] => [abc,def,hij,xxx]
_currentCount = 0;
crawArticleDetail(detailUrlArr,res);
return false;
});
}
Здесь ссылка на пользовательский центр идет из файла config, мы используемasync.mapLimitДавайте выполним контроль параллелизма при сканировании, и максимальное количество параллелизма равно 5.
async.mapLimitИспользование:mapLimit(arr, limit, iterator, callback);
arr: множество
limit: количество одновременных
iterator: Итератор (функция обработки), здесь относится к однократному обходу пользовательского центра, он содержитобратный вызов должен быть выполнени сохранить результат этого выполнения.
callback:
Обратный вызов после завершения выполнения. После захвата всех пользовательских центров этому обратному вызову будут возвращены все захваченные результаты.
Получите коллекцию сведений о статье за определенный период времени из пользовательского центра:
// 获取某个时间段文章链接集合
const getDetailUrlCollections = ($,startTime,endTime) => {
let articleList = $('#list-container .note-list li'),
detailUrlCollections = [];
for(let i = 0,len = articleList.length; i < len; i++) {
let crateAt = articleList.eq(i).find('.author .time').attr('data-shared-at');
let createTime = new Date(crateAt).getTime();
if(createTime >= startTime && createTime <= endTime) {
let articleUrl = articleList.eq(i).find('.title').attr('href');
let url = _baseUrl + articleUrl;
detailUrlCollections.push(url);
}
}
return detailUrlCollections;
}
5. На шаге 4 мы получили все ссылки на сведения о статье, поэтому давайте просканируем содержимое сведений о статье, что аналогично шагу 4.
// 爬取文章详情
const crawArticleDetail = (detailUrls,res) => {
const detailUrlArr = spreadDetailUrl(detailUrls);
async.mapLimit(detailUrlArr, 5, (url, callback) => {
_currentCount ++;
fetchUrl(url, (html) => {
const $ = cheerio.load(html,{decodeEntities: false});
const data = {
title: $('.article .title').html(),
wordage: $('.article .wordage').html(),
publishTime: $('.article .publish-time').html(),
author: $('.author .name a').html()
};
callback(null,data);
});
}, (err, resData) => {
let result = removeSame(resData);
const sumUpData = sumUpResult(result);
res.json({
data: result,
sumUpData: sumUpData
});
createExcel(result,sumUpData);
console.info('抓取数据完毕,一共抓取了:'+ result.length +'篇文章,其中,错误数为:' + _errorUrls.length +'条');
if(_errorUrls.length > 0) {
console.info('错误的url为:' + _errorUrls.join(','));
}
return false;
});
}
// [[abc,def],[hij,xxx]] => [abc,def,hij,xxx]
const spreadDetailUrl= (urls) => {
const urlCollections = [];
urls.forEach((item) => {
item.forEach((url) => {
urlCollections.push(url);
})
});
return urlCollections;
}
Из деталей статьи мы получаем заголовок, количество слов, время публикации, конечно, вы можете получить нужную информацию на странице, мне здесь не нужно слишком много, этого достаточно. Полученные здесь данные повторяются, поэтому нам нужно провести дедупликацию массива
6. На этом этапе все данные, которые нам нужны для сканирования, получены.На последнем шаге мы создадим таблицу Excel.
Я использовал узел для создания листа Excel, осмотрелся и обнаружил, чтоejsexcelЭтот фреймворк имеет хорошие оценки.Нажмите, чтобы просмотреть;
Его использование заключается в следующем: сначала нам нужен шаблон листа Excel, а затем в шаблоне мы можем использовать синтаксис ejs для создания таблицы в соответствии с нашим значением.
// 生成excel表
const createExcel = (dataArr,sumUpData) => {
const exlBuf = fs.readFileSync(config.excelFile.path + "/report.xlsx");
//数据源
const data = [ [{"table_name":"7班简书统计表","date": formatTime()}], dataArr, sumUpData ];
//用数据源(对象)data渲染Excel模板
ejsExcel.renderExcel(exlBuf, data)
.then(function(exlBuf2) {
fs.writeFileSync(config.excelFile.path + "/report2.xlsx", exlBuf2);
console.log("生成excel表成功");
}).catch(function(err) {
console.error('生成excel表失败');
});
}
Сначала прочитайте наш шаблон, затем запишите наши данные в шаблон, чтобы создать новый лист Excel.
7. Поскольку время сканирования не фиксировано, мы делаем весь процесс сканирования в форме внешнего ajax-запроса и передаем два данных startTime и endTime.Внешний интерфейс относительно прост.
Сгенерированная схема таблицы Excel:
Процесс захвата выглядит следующим образом:
На данный момент наш короткий поисковый робот завершен, что относительно просто.
будь осторожен:
Поскольку можно захватить только первую страницу данных в пользовательском центре, лучше всего выбрать время на предыдущей неделе. А при формировании листа excel необходимо закрыть excel, иначе генерация листа excel будет неудачной.
Код выложен на github, добро пожаловать в использование (надеюсь, Jianshu меня не заблокирует):перейти на гитхаб.
Кстати, имя этой рептилии: Шмель