title: PDF scraping using textract module
body: <p>I have a Node.js app that have to do some web scraping of online pdf.
  This is a piece of code:</p>
  
  <pre><code>var textract = require('textract');
  const util = require('util');
  
  var methods = {};
  
  var urls = [
      {year: '2016', link: 'http://www.url2016.pdf'},
      {year: '2015', link: 'http://www.url2015.pdf'}
  ];
  var result = [];
  
  const textractFromUrl = util.promisify(textract.fromUrl);
  
  
  methods.download = function(req, res) {
      return extractText();
  }
  
  async function extractText() {
      try {
          var config = {
              preserveLineBreaks: true
          };
          for(let url of urls) {
              let text = await textractFromUrl(url.link, config);
              switch(url.year) {
                  case '2015':
                      await extractTextType1(url, text);
                      break;
  
                  case '2016':
                      await extractTextType2(url, text);
                      break;
  
                  default:
                      console.log('Error: no switch case');
              }
          }
      }
      catch(err) {
          console.log('catch block');
          console.log(err);
      }
  }
  </code></pre>
  
  <p>As you can see, I use <code>textrack</code> package to scrape pdf.
  When I run this app, I get: </p>
  
  <pre><code>catch block
  { Error: Error for type: [[ application/pdf ]], file: [[ C:\Users\myUserName\AppData\Local\Temp\96710848773.pdf ]], extractor for type exists, but failed to initialize. Message: INFO: 'pdftotext' does not appear to be installed, so textract will be unable to extract PDFs.
      at extract (C:\Users\myUserName\projectPath\node_modules\textract\lib\extract.js:147:15)
      at Timeout._onTimeout (C:\Users\myUserName\projectPath\node_modules\textract\lib\extract.js:155:7)
      at ontimeout (timers.js:466:11)
      at tryOnTimeout (timers.js:304:5)
      at Timer.listOnTimeout (timers.js:267:5) typeNotFound: true }
  </code></pre>
  
  <p>In the <a href="https://www.npmjs.com/package/textract" rel="nofollow noreferrer">npm textract module page</a>, is written that <strong>PDF extraction requires pdftotext be installed, <a href="http://www.foolabs.com/xpdf/download.html" rel="nofollow noreferrer">link</a></strong>.</p>
  
  <p>So I go to <a href="http://www.foolabs.com/xpdf/download.html" rel="nofollow noreferrer">http://www.foolabs.com/xpdf/download.html</a> and I downloaded and istalled <strong>Download XpdfReader: Windows 64-bit</strong>.</p>
  
  <p>I try again to run the app using <code>node app.js</code> (<code>app.js</code> is the main file of my app) but I get the same error so I download <strong>Download the Xpdf tools: Windows 64-bit</strong>. </p>
  
  <p>It's a zip file, I extract that file and then I try to install <code>pdftotext.exe</code> but when I double click on <code>pdftotext.exe</code>, anything happens.
  I also try to install that using Administrator privileges. Nothing.</p>
  
  <p>I'm using Windows 10, 64 bit.</p>
  
  <p>What I have to do?</p>
  
  <hr>
  
  <h1>EDIT 1</h1>
  
  <p>As recommended, I copied the <code>pdftotext.exe</code> file to <code>C:\Windows\System32</code>. Then I ran my program again and I have this problem:</p>
  
  <pre><code>catch block
  TypeError: Cannot read property 'split' of undefined
      at extractTextType4 (C:\myUserName\projectPath\file.js:301:28)
      at extractText (C:\myUserName\projectPath\file.js:78:12)
      at &lt;anonymous&gt;
      at process._tickCallback (internal/process/next_tick.js:182:7)
  </code></pre>
  
  <p>Do I have to change the environment variables?</p>
  
  <hr>
  
  <h1>EDIT 2</h1>
  
  <p>My <code>C:\myUserName\projectPath\file.js</code> is this:</p>
  
  <pre><code>var textract = require('textract');
  const util = require('util');
  var utilFunc = require('../helpers/utilFunc.js'); // my lib
  var postgreSQLlib = require('../middlewares/postgreSQLlib.js'); // my lib
  
  // object of methods
  var methods = {};
  
  // object of pdf links
  var urls = [
      {year: '2014', link: 'http://www.salute.gov.it/imgs/C_17_tavole_20_allegati_iitemAllegati_0_fileAllegati_itemFile_2_file.pdf'}, 
      {year: '2013', link: 'http://www.salute.gov.it/imgs/C_17_tavole_20_allegati_iitemAllegati_0_fileAllegati_itemFile_1_file.pdf'}, 
      {year: '2012', link: 'http://www.salute.gov.it/imgs/C_17_tavole_20_allegati_iitemAllegati_5_fileAllegati_itemFile_0_file.pdf'}
  ];
  var result = [];
  
  const textractFromUrl = util.promisify(textract.fromUrl);
  
  /**
   * Do web scraping and save info on DB.
   */
  methods.download = function(req, res) {
      return extractText();
  }
  
  /**
   * Switch between different type of pdf file.
   */
  async function extractText() {
      try {
          var config = {
              preserveLineBreaks: true
          };
          for(let url of urls) {
              let text = await textractFromUrl(url.link, config);
              switch(url.year) {
                  case '2012':
                      await extractTextType1(url, text);
                      break;
  
                  case '2013': 
                      await extractTextType2(url, text);
                      break;
  
                  case '2014': 
                      await extractTextType3(url, text);
                      break;
  
                  default:
                      console.log('Error: no switch case');
              }
          }
      }
      catch(err) {
          console.log('catch block');
          console.log(err);
      }
  }
  
  /**
   * Save data on DB.
   */
  function saveOnObject(vaccines, regions, map, url) {
      vaccines = map.shift(); // remove and return the first element 
      regions = map.shift(); // remove and return the first element 
  
      let promises = [];
      for(var i = 0; i &lt;= 21; i++) {
          var line = map[i]; 
          line.forEach(async function(value, index) { 
  
              // make the values uniform
              var vac = utilFunc.makeUniform(vaccines[index], 'vaccine');
              var reg = utilFunc.makeUniform(regions[i], 'region');
              var perc = utilFunc.makeUniform(value, 'value');
  
              // create json object
              var obj = utilFunc.createJsonObjectCov(parseFloat(url.year), 'Italy', vac, reg, perc);
              covDataItAll.push(obj);
          });
      }
      return Promise.all(promises);
  }
  
  /**
   * Extract text to pdf 2000-2012.
   */
  function extractTextType1(url, text) {
      var matrix = [];
      var map = [];
      var vaccines = [];
      var regionsTemp = [];
      var regions = [];
      var regionLength = [1, 2, 1, 2, 3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; 
  
      // text to matrix
      var textArray = text.split('\n');
      for(var i = 0; i &lt; 23; i++) {
          matrix[i] = textArray[i].split(' ');
      }
  
      // create vaccines array
      matrix[0].shift();
      vaccines = matrix[0];
      map[0] = vaccines;
  
      // create regionsTemp and values arrays 
      for(var i = 0; i &lt; regionLength.length; i++) { // i index for regionLength
          var j = i + 1; // index for matrix
          var indexToRemove = 0;
          var numberToRemove = regionLength[i];
          var region = matrix[j].splice(indexToRemove, numberToRemove);
          regionsTemp.push(region);
          map[j+1] = matrix[j];
      }
  
      // create regions array (merge some elements)
      for(var i = 0; i &lt; regionsTemp.length; i++) {
          var region = '';
          if(regionLength[i] &gt; 1) {
              region = regionsTemp[i].join(' ');
          }
          else {
              region = regionsTemp[i].join('');
          }
          regions.push(region);
      }
      map[1] = regions;
  
      // remove \r char from map
      for(var i = 0; i &lt; map.length; i++) {
          for(var j = 0; j &lt; map[i].length; j++) {
              map[i][j] = map[i][j].replace(/\r/g, '');
          }
      }
  
      return saveOnObject(vaccines, regions, map, url);
  }
  
  /**
   * Extract text to pdf 2013.
   */
  function extractTextType2(url, text) {
      var matrix = [];
      var map = [];
      var vaccines = [];
      var regions = [];
  
      // text to matrix
      var textArray = text.split('\n');
      for(var i = 0; i &lt; 36; i++) {
          matrix[i] = textArray[i].split(' ');
      }
  
      // create vaccines array
      vaccines.push(matrix[0][1].replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, ''));
      for(var i = 1; i &lt; 10; i++) {
          vaccines.push(matrix[i][0].replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, ''));
      }
      var meningo = ''.concat(matrix[10][0], matrix[11]).replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, '');
      vaccines.push(meningo);
      var pneumo = ''.concat(matrix[12][0], ' ', matrix[13]).replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, '');
      vaccines.push(pneumo);
      map[0] = vaccines;
  
      // create regions array
      for(var i = 14; i &lt; matrix.length; i++) { 
          regions.push(matrix[i][0]);
      }
      map[1] = regions;
  
      // create values array
      for(var i = 14; i &lt; matrix.length; i++) {
          matrix[i].shift();
          map.push(matrix[i]);
      }
  
      // remove \r char from map
      for(var i = 0; i &lt; map.length; i++) {
          for(var j = 0; j &lt; map[i].length; j++) {
              map[i][j] = map[i][j].replace(/\r/g, '');
          }
      }
  
      return saveOnObject(vaccines, regions, map, url);
  }
  
  /**
   * Extract text to pdf 2014.
   */
  function extractTextType3(url, text) {
      var matrix = [];
      var map = [];
      var vaccines = [];
      var regionsTemp = [];
      var regions = [];
      var regionLength = [1, 2, 1, 3, 3, 1, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]; // array that contains the length of the regions (I need to correctly split the arrays)
  
      // text to matrix
      var textArray = text.split('\n');
  
      for(var i = 0; i &lt; 36; i++) {
          matrix[i] = textArray[i].split(' ');
      }
  
      // create vaccines array
      vaccines.push(matrix[0][2].replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, ''));
      for(var i = 1; i &lt; 10; i++) {
          vaccines.push(matrix[i][0].replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, ''));
      }
      var meningo = ''.concat(matrix[10][0], ' ', matrix[10][1], ' ', matrix[11]).replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, '');
      vaccines.push(meningo);
      var pneumo = ''.concat(matrix[12][0], ' ', matrix[13]).replace(/\(a\)/g, '').replace(/\(b\)/g, '').replace(/\(c\)/g, '').replace(/\r/g, '');
      vaccines.push(pneumo);
      map[0] = vaccines;
  
      // create regionsTemp and values arrays 
      for(var i = 0; i &lt; regionLength.length; i++) { // i index for regionLength
          var j = i + 14; // index for matrix
          var indexToRemove = 0;
          var numberToRemove = regionLength[i];
          var region = matrix[j].splice(indexToRemove, numberToRemove);
          regionsTemp.push(region);
          map[i+2] = matrix[j];
      }
  
      // create regions array (merge some elements)
      for(var i = 0; i &lt; regionsTemp.length; i++) {
          var region = '';
          if(regionLength[i] &gt; 1) {
              region = regionsTemp[i].join(' ');
          }
          else {
              region = regionsTemp[i].join('');
          }
          regions.push(region);
      }
      map[1] = regions;
  
      // remove \r char from map
      for(var i = 0; i &lt; map.length; i++) {
          for(var j = 0; j &lt; map[i].length; j++) {
              map[i][j] = map[i][j].replace(/\r/g, '');
          }
      }
  
      return saveOnObject(vaccines, regions, map, url);
  }
  
  // exports methods
  module.exports = methods;
  </code></pre>