How does lexical analyzer remove white spaces from source file?
A brief answer is "by ignoring them".
A compiler may scan the entire code more than once, but of course at least once in which case we call it a single-pass compiler. The task of lexical analyzer (or sometimes called simply scanner) is to generate tokens. This is done simply by scanning the entire code (in linear manner by loading it for example into an array) from the beginning to the end symbol-by-symbol and grouping them into tokens. Thus, while checking each symbol (of the source code) you just skip the white-space symbols. Similarly you skip comments in the source code.  

As to my personal experience, I had to implement a single-pass compiler for a made-up simple language which allowed both white space symbols (TAB, NEW-LINE, SPACE) and comments. I loaded the entire source code into a linear array and as my lexical analyzer went over the code character by character it simply skipped all white space symbols and comments by moving forward the pointer pointing to the current character.

But depending on the implementation you could first pass over the source code just to remove all white spaces, and then on the second pass generate tokens.    

Caution:  "ignoring whitespace" shouldn't be interpreted as "remove all white space symbols from the source and then further process the source code". In some cases depending on the language construct white spaces may indicate when a token ends for example in the following piece of code 

  int foo(int x)
  {
    return x+2;
  }


The tokens TYPE (int) and the IDENTIFIER (foo) are separated by a single SPACE. But the IDENTIFIER (foo) and immediate LEFTPAR are not separated by any white space symbol. 

Also (on Derek Elkins' comment) real compilers usually use whitespace for producing clear error messages, for example for keeping track of line numbers.