Рубрики
Без рубрики

Как я просматривал 7000 статей с веб-сайта газеты с помощью узла

Почему я сделал это? Моя подруга пишет бумагу о восприятии французской хип-хоп музыки через время. Для этого она хотела бы помириться в текстовые шахты из Lemonde.fr, французская основная газета. Проблема: Прошло более 7 000 статей, говорящих о музыке хип-хоп, так как

Автор оригинала: Alexandre Robin.

Почему я сделал это?

Моя подруга пишет бумагу о восприятии французской музыки хип-хоп через время. Для этого она хотела бы помириться в текстовые шахты из Lemonde.fr, французская основная газета.

Проблема : Было больше, чем 7000 статей Говоря о хип-хоп музыке с 80-х годов.

Давайте код!

Для этой программы я буду использовать:

  • Скрипт местных нодей
  • фшс: Чтобы написать файл json
  • Запрос : сделать сообщение и получить Запросы
  • Cheerio : загрузить HTML и иметь возможность взаимодействовать с ним
//To install cheerio :npm i --save cheerio

Убедитесь, что у вас все это в вашем пакете. Джусон, и все должно быть хорошо:)

Что я хотел? В конце концов, я хотел, чтобы файл Excel организован, как это:

Поэтому я должен был использовать JSON Structured, как это. Я покажу вам в конце этой статьи, как конвертировать JSON в Excel.

[
 {
 ‎ date:,
  title:,
  description:,
 ‎ text:,
 ‎ url:,
 ‎},
]

Первый шаг: получите URL все статьи

Первый шаг был довольно легким. Благодаря расширенной функции поиска, мне просто пришлось получить ссылку URL страницы результата и сообщите моим коде, как:

  • Ищите количество результатов
  • Рассчитайте количество страниц, зная, что на странице 30 статей
  • Получите название, описание, дату и URL-адрес 30 статей для каждой страницы

Вот код для этого:

const fs = require("fs");
const request = require("request");
const cheerio = require("cheerio");

const jsonTab = []; // We create our table

function writeFile() {
  // Will write the json file
  fs.writeFile("output.json", JSON.stringify(jsonTab, null, 4), (err) => {
    console.log("File successfully written!");
  });
}

// The URL of the advanced search feature with our keywords
const url = 'http://www.lemonde.fr/recherche/?keywords="Rap+"+"hip-hop"+"hip%20hop"+"rappeur"+"rappeurs"+"raps"+"rappers"&page_num=1&operator=or&exclude_keywords=&qt=recherche_texte_title&author=&period=custom_date&start_day=01&start_month=01&start_year=1970&end_day=20&end_month=09&end_year=2017&sort=asc';

/* The first request call, our goal here is to get the number of results and then
to calculate the number of pages */
request(url, (error, response, html) => {
  const $ = cheerio.load(html);

  // All the variables we will use later
  let number;
  let description;
  let date;
  let title;
  let link;

  if (!error) {
    $(".bg_gris_clair").filter(() => {
      /* We want to select all the HTML
      elements with the class ".bg_gris_clair" (and we already know there is
      only one) */
      const data = $(this);
      const str = data.children("strong").text().trim();
      number = parseInt(str.substring(0, str.indexOf("e")).replace(/\s/g, ""), 10);
    });
  }

  let count = 1;

  for (let i = 1; i <= number / 10; i++) {
    const urlPerPage = 'http://www.lemonde.fr/recherche/?keywords="Rap+"+"hip-hop"+"hip%20hop"+"rappeur"+"rappeurs"+"raps"+"rappers"&page_num=' + i + "&operator=or&exclude_keywords=&qt=recherche_texte_title&author=&period=custom_date&start_day=01&start_month=01&start_year=1970&end_day=20&end_month=09&end_year=2017&sort=asc";

    request(urlPerPage, (err, response2, html2) => {
      if (!err) {
        const $ = cheerio.load(html2);

        $(".grid_11.omega.resultat").filter(() => {
          const json = {
            date: "",
            title: "",
            description: "",
            url: ""
          };
          const data = $(this);

          title = data.children("h3").children("a").text().trim();
          link = "http://lemonde.fr" + data.children("h3").children("a").attr("href").trim();
          description = data.children("p").text().trim();
          const dateStr = data.children("span").text();
          date = dateStr.replace(/.+?(?=\d)/, "");

          json.title = title;
          json.url = link;
          json.description = description;
          json.date = date;
          jsonTab.push(json);
        });
      } else if (err) {
        console.log(err);
      }

      count += 1;

      // Write the file once we iterated through all the pages.
      if (count === parseInt(number / 10, 10)) {
        writeFile();
      }
    });
  }
});

Однажды я сделал это, у меня был файл JSON с более чем 7000 записей. Для каждого из них у меня было:

  • Свидание
  • Заголовок
  • Описание
  • URL-адрес

Мне просто не хватало контента …

” Хорошо, мне просто нужно использовать тот же код и запустить его для 7000 URL-адресов, которые я должен получить контент! »

Я принимал активно участвовать в коде на один год сейчас … И одно из первых, что я узнал, был: Ничто никогда не просто в коде Отказ Всегда. Но для каждой проблемы вы Будет ли Борьба с, есть вопрос, который вы можете Google ;-).

Я обнаружил, что огромная часть изделий не была доступна без премиум-аккаунта. Поэтому я должен был быть связан с возможностью просмотра контента и соскребать его.

К счастью, нам удалось получить премиум-аккаунт. Мне просто пришлось найти способ сказать свой код, как:

  • Аутентифицироваться на Lemonde.fr.
  • Оставаться на связи во время соскабливания

Шаг вторая: как аутентифицировать на веб-сайте

Для этого мне нужно было понять, как работает сайт, когда я нажимаю на «Войти». ” Хорошая новость: у нас есть инструменты разработчика.

Мне просто нужно было узнать, как сайт отправляет пароль и имя пользователя на сервер и воспроизвести шаблон.

Вот страница аутентификации LEMONDE.FR (как это французская платформа, я перевел несколько слов, чтобы помочь вам понять):

Теперь, что происходит, когда мы пытаемся войти?

Ты это видел? Я нажал на «Логин» и Lemonde.fr Отправляет почтовый запрос с простой формой, содержащей пять битов информации:

  • Соединение [Mail]
  • Соединение [пароль]
  • Соединение [acte_connected]: 1 for true, 0 для false (hint: вы хотите, чтобы он был правдой)
  • Соединение [Сохранить] Требуется здесь
  • Соединение [токен] – это сложная часть

Мы уже знаем четыре бита информации из пяти. Мы просто должны найти, откуда приходит «токен».

К счастью, Lemonde.fr приятно нам ☺️:

Токен подключения автоматически генерируется в скрытом входе при запуске страницы в первый раз. Вы просто должны это знать и получить его, прежде чем пытаться войти в систему.

Ну, мы теперь готовы перейти к шагу 3!

Шаг три: должен ловить их все!

Вот полный код для аутентификации, извлечения и хранения файлов cookie и, наконец, собирать все статьи.

const fs = require("fs");
const request = require("request");
const cheerio = require("cheerio");

// Prepare all the variables needed later
let count = 0;
let timeout = 0;
const id = "myusername";
const mdp = "mypassword";
let obj;

// The URLs we will scrape from
const connexionUrl = "https://secure.lemonde.fr/sfuser/connexion";

// Will write an "output.json" file
function writeFile() {
  fs.writeFile("output.json", JSON.stringify(obj, null, 4), (err) => {
    console.log(
      "File successfully written! - Check your project directory for the output.json file"
    );
  });
}

// creating a clean jar to store the cookies
const j = request.jar();

// First Get Request Call
request(
  {
    url: connexionUrl,
    jar: j
  },
  (err, httpResponse, html) => {
    const $ = cheerio.load(html);

    // We use Cheerio to load the HTML and be able to find the connection__token
    const token = $("#connection__token")[0].attribs.value; // here is the connection__token

    // Construction of the form required in the POST request to login
    const form = {
      "connection[mail]": id,
      "connection[password]": mdp,
      "connection[stay_connected]": 1,
      "connection[save]": "",
      "connection[_token]": token
    };

    // POST REQUEST to Log IN. Same url with "request headers" and the complete form.
    request.post(
      {
        url: connexionUrl,
        jar: j,
        headers: {
          Accept:
            "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4",
            "Cache-Control": "no-cache",
            "Content-Type": "application/x-www-form-urlencoded",
            Origin: "http://secure.lemonde.fr/",
            Host: "secure.lemonde.fr",
            "Upgrade-Insecure-Requests": 1,
            "User-Agents":
            "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0",
          Connection: "keep-alive",
          Pragma: "no-cache",
          Referer: "https://secure.lemonde.fr/sfuser/connexion"
        },

        form: form
      },
      (error, response, body) => {
        // WE ARE CONNECTED :D

        /* Second GET request call : this time, we use the response of the POST
        request to request the right URL */
        request(
          {
            url: response.headers.location,
            jar: j
          },
          (err, httpResponse, html2) => {
            const json = fs.readFileSync("./firstStep.json"); // Load the JSON created in step one
            obj = JSON.parse(json); // We create our JSON in a usable javascript object

            // forEach loop to iterate through all the object and request each link
            obj.forEach((e) => {
              let articleUrl = e.url;

              /* We use a setTimeout to be sure that all the requests are performed
              one by one and not all at the same time */
              setTimeout(() => {
                request(
                  {
                    url: articleUrl,
                    jar: j
                  },
                  (error1, httpResponse, html3) => {
                    if (!error1) {
                      const $ = cheerio.load(html3); // load the HTML of the article page
                      $(".contenu_article.js_article_body").filter(() => {
                        const data = $(this);

                        // get the content, remove all the new lines (better for Excel)
                        let text = data
                          .text()
                          .trim()
                          .replace(/\n/g, "\t");

                        e.text = text; // push the content in the table
                      });

                      $(".txt3.description-article").filter(() => {
                        const data = $(this);

                        const description = data
                          .text()
                          .trim()
                          .replace(/\n/g, "\t");

                        e.description = description;
                      });
                    }
                  }
                );

                count += 1;

                // Write a new JSON file once we get the content of all the articles
                if (count === obj.length) {
                  writeFile();
                }
              }, timeout);

              timeout += 50; // increase the timeout length each time
            });
          }
        );
      }
    );
  }
);

Теперь у меня есть файл JSON со всеми статьями и их содержанием. Последний шаг – преобразовать его в реальную таблицу Excel.

Бонус шаг четвертый: От .json до .csv

Вот простой код для преобразования файла «yource.json» на «yource.csv» (вы можете поблагодарить моего друга @jvdsande. ):

const fs = require('fs');

let jsonstring = fs.readFileSync('output.json') // load the output.json file
let json = JSON.parse(jsonstring)


function JSONtoCSV(JSON) {
  let CSV = ''

  Object.keys(JSON[0]).forEach((key) => {
    CSV += key + '§'
  })

  CSV += '\r\n'

  JSON.forEach((obj) => {
    Object.keys(obj).forEach((key) => {
      CSV += obj[key] + '§'
    })

    CSV += '\r\n'
  })

  return CSV
}

fs.writeFileSync('output.csv', JSONtoCSV(json))

И это так. Я могу импортировать свой файл «Output.csv» в Excel, и у меня есть то, что я хотел: 7000+ строк заполнены статьями из Lemonde.fr

Вы хотите узнать самую лучшую часть? Я уверен, что эта логика легко многоразовая для всех газетных сайтов в мире!

Если вы хотите создать базу данных или Scrape веб-сайт, не стесняйтесь обращаться ко мне через Twitter или LinkedIn, я был бы рад помочь вам.

Ой! И я работаю над боковым проектом, чтобы повторно повторно повторно использовать все, что я узнал здесь с LinkedIn, чтобы улучшить скорость поиска для рекрутеров:)

Спасибо за чтение, это моя первая история на среднем, и я был бы взволнован, чтобы узнать ваше мнение об этом!

Оригинал: “https://www.freecodecamp.org/news/how-i-scraped-7000-articles-from-a-newspaper-website-using-node-1309133a5070/”