我经常收到关于email爬虫的问题。有迹象表明那些想从网页上抓取联系方式的人对这个问题很感兴趣。在这篇文章里,我想演示一下如何使用python实现一个简单的邮箱爬虫。这个爬虫很简单,但从这个例子中你可以学到许多东西(尤其是当你想做一个新虫的时候)。

  我特意简化了代码,尽可能的把主要思路表达清楚。这样你就可以在需要的时候加上自己的功能。虽然很简单,但完整的实现从网上抓取email地址的功能。注意,本文的代码是使用python3写的。

  好。让我们逐步深入吧。我一点一点的实现,并加上注释。最后再把完整的代码贴出来。

  首先引入所有必要的库。在这个例子中,我们使用的BeautifulSoup 和 Requests 是第三方库,urllib, collectionsre 是内置库。

BeaufulSoup可以使检索Html文档更简便,Requests让执行web请求更容易。

from bs4 import BeautifulSoup
import requests
import requests.exceptions
from urllib.parse import urlsplit
from collections import deque
import re

  下面我定义了一个列表,用于存放要抓取的网页地址,比如http://www.huazeming.com/ ,当然你也可以找有明显email地址的网页作为地址,数量不限。虽然这个集合应该是个列表(在python中),但我选择了 deque 这个类型,因为这个更符合我们的需要。

# a queue of urls to be crawled
new_urls = deque(['http://www.themoscowtimes.com/contact_us/'])

  接下来,我们需要把处理过的url存起来,以避免重复处理。我选择set类型,因为这个集合可以保证元素值不重复。

  

# a set of urls that we have already crawled
processed_urls = set()

  定义一个email集合,用于存储收集到地址:

# a set of crawled emails
emails = set()

  让我们开始抓取吧!我们有一个循环,不断取出队列的地址进行处理,直到队列里没有地址为止。取出地址后,我们立即把这个地址加到已处理的地址列表中,以免将来忘记。

# process urls one by one until we exhaust the queue
while len(new_urls):
# move next url from the queue to the set of processed urls
url = new_urls.popleft()
processed_urls.add(url)

  然后我们需要从当前地址中提取出根地址,这样当我们从文档中找到相对地址时,我们就可以把它转换成绝对地址。

# extract base url and path to resolve relative links
parts = urlsplit(url)
base_url = "{0.scheme}://{0.netloc}".format(parts)
path = url[:url.rfind('/')+1] if '/' in parts.path else url

  下面我们从网上获取页面内容,如果遇到错误,就跳过继续处理下一个网页。

# get url's content
print("Processing %s" % url)
try:
response = requests.get(url)
except (requests.exceptions.MissingSchema, requests.exceptions.ConnectionError):
# ignore pages with errors
continue

  当我们得到网页内容后,我们找到内容里所有email地址,把其添加到列表里。我们使用正则表达式提取email地址:

# extract all email addresses and add them into the resulting set
new_emails = set(re.findall(r"[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+", response.text, re.I))
emails.update(new_emails)

  在我们提取完当前网页内容的email地址后,我们找到当前网页中的其他网页地址,并将其添加到带处理的地址队列里。这里我们使用BeautifulSoup库来分析网页html。

# create a beutiful soup for the html document
soup = BeautifulSoup(response.text)

  这个库的find_all方法可以根据html标签名来抽取元素。

# find and process all the anchors in the document
for anchor in soup.find_all("a"):

  但网页总的有些a标签可能不包含url地址,这个我们需要考虑到。

# extract link url from the anchor
link = anchor.attrs["href"] if "href" in anchor.attrs else ''

  如果这个地址以斜线开头,那么我们把它当做相对地址,然后给他加上必要的根地址:

# add base url to relative links
if link.startswith('/'):
link = base_url + link

  到此我们得到了一个有效地址(以http开头),如果我们的地址队列没有,而且之前也没有处理过,那我们就把这个地址加入地址队列里:

# add the new url to the queue if it's of HTTP protocol, not enqueued and not processed yet
if link.startswith('http') and not link in new_urls and not link in processed_urls:
new_urls.append(link)

  好,就是这样。以下是完整代码:

from bs4 import BeautifulSoup
import requests
import requests.exceptions
from urllib.parse import urlsplit
from collections import deque
import re # a queue of urls to be crawled
new_urls = deque(['http://www.themoscowtimes.com/contact_us/index.php']) # a set of urls that we have already crawled
processed_urls = set() # a set of crawled emails
emails = set() # process urls one by one until we exhaust the queue
while len(new_urls): # move next url from the queue to the set of processed urls
url = new_urls.popleft()
processed_urls.add(url) # extract base url to resolve relative links
parts = urlsplit(url)
base_url = "{0.scheme}://{0.netloc}".format(parts)
path = url[:url.rfind('/')+1] if '/' in parts.path else url # get url's content
print("Processing %s" % url)
try:
response = requests.get(url)
except (requests.exceptions.MissingSchema, requests.exceptions.ConnectionError):
# ignore pages with errors
continue # extract all email addresses and add them into the resulting set
new_emails = set(re.findall(r"[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+", response.text, re.I))
emails.update(new_emails) # create a beutiful soup for the html document
soup = BeautifulSoup(response.text) # find and process all the anchors in the document
for anchor in soup.find_all("a"):
# extract link url from the anchor
link = anchor.attrs["href"] if "href" in anchor.attrs else ''
# resolve relative links
if link.startswith('/'):
link = base_url + link
elif not link.startswith('http'):
link = path + link
# add the new url to the queue if it was not enqueued nor processed yet
if not link in new_urls and not link in processed_urls:
new_urls.append(link)

  这个爬虫比较简单,省去了一些功能(比如把邮箱地址保存到文件中),但提供了编写邮箱爬虫的一些基本原则。你可以尝试对这个程序进行改进。

  当然,如果你有任何问题和建议,欢迎指正!

  英文原文:A Simple Email Crawler in Python

实现一个简单的邮箱地址爬虫(python)的更多相关文章

  1. 用一个简单的例子来理解python高阶函数

    ============================ 用一个简单的例子来理解python高阶函数 ============================ 最近在用mailx发送邮件, 写法大致如 ...

  2. 一个简单的开源PHP爬虫框架『Phpfetcher』

    这篇文章首发在吹水小镇:http://blog.reetsee.com/archives/366 要在手机或者电脑看到更好的图片或代码欢迎到博文原地址.也欢迎到博文原地址批评指正. 转载请注明: 吹水 ...

  3. 一个简单、易用的Python命令行(terminal)进度条库

    eprogress 是一个简单.易用的基于Python3的命令行(terminal)进度条库,可以自由选择使用单行显示.多行显示进度条或转圈加载方式,也可以混合使用. 示例 单行进度条 多行进度条 圆 ...

  4. [Python Study Notes]一个简单的区块链结构(python 2.7)

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ...

  5. 一个简单的app自动登录Python脚本案例

  6. 一个简单的go语言爬虫

    package main import ( "bufio" "fmt" "golang.org/x/net/html/charset" &q ...

  7. Python学习手册之正则表达式示例--邮箱地址提取

    在上一篇文章中,我们介绍了 Python 的捕获组和特殊匹配字符串,现在我们介绍 Python 的正则表达式使用示例.查看上一篇文章请点击:https://www.cnblogs.com/dustma ...

  8. 使用James搭建一个自己的邮箱服务器

    ---第一天开发--- 下载Apache James 3.0邮箱服务器,解压到响应的目录 可以看到目录结构: H:\code\JavaCode\James\apache-james-3.0-beta4 ...

  9. 一个简单的python爬虫,爬取知乎

    一个简单的python爬虫,爬取知乎 主要实现 爬取一个收藏夹 里 所有问题答案下的 图片 文字信息暂未收录,可自行实现,比图片更简单 具体代码里有详细注释,请自行阅读 项目源码: # -*- cod ...

随机推荐

  1. [11-3] Gradient Boosting regression

    main idea:用adaboost类似的方法,选出g,然后选出步长 Gredient Boosting for regression: h控制方向,eta控制步长,需要对h的大小进行限制 对(x, ...

  2. iOS中通知传值

    NSNotification 通知中心传值,可以跨越多个页面传值, 一般也是从后面的页面传给前面的页面.   思路: 第三个界面的值传给第一个界面. 1. 在第一个界面建立一个通知中心, 通过通知中心 ...

  3. hdu 5586 Sum(dp+技巧)

    Problem Description There )mod10007.After that,the sum of n numbers should be as much as possible.Wh ...

  4. Java压缩技术的学习

    由于工作的需要,经常要手动去打上线安装包,为了方便,自己写程序去帮助打包.使用过Unix或者Linux的人都基本上都用过tar打包以及gzip压缩,但在Windows下使用得最多的压缩还是RAR和Zi ...

  5. Love Hotels and Unicode[转]

    原文地址:http://www.reigndesign.com/blog/love-hotels-and-unicode/ 讲得挺通俗的一篇文章 On Sunday 28 October I atte ...

  6. Web设计中打开新页面或页面跳转的方法 js跳转页面

    Web设计中打开新页面或页面跳转的方法 一.asp.net c# 打开新页面或页面跳转 1. 最常用的页面跳转(原窗口被替代):Response.Redirect("newpage.aspx ...

  7. .net通用权限框架C/S概览

    通用权限框架cs部分 先概述一下,cs使用vs2010+sql2008 和bs公用同一个数据库 为使界面好看使用了第三方控件 donetbar和devexpress,正版是要收费的,但是你们都明白的可 ...

  8. 20151205--JDBC-2

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  9. Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

  10. js工具常用方法

    /* function obj$(id) 根据id得到对象 function val$(id) 根据id得到对象的值 function trim(str) 删除左边和右边空格 function ltr ...