我想抓取并将一些网页保存为HTML。比如说,爬进数百个热门网站,只需保存他们的前台和“关于”页面。
我已经研究了很多问题,但没有从网页抓取或网页抓取问题中找到答案。
我应该使用什么库或工具来构建解决方案?或者甚至有一些现有的工具可以解决这个问题吗?
答案 0 :(得分:6)
在使用Python时,您可能会对mechanize和BeautifulSoup感兴趣。
机械化类似于模拟浏览器(包括代理,伪造浏览器标识,页面重定向等选项)并允许轻松获取表单,链接,......文档有点粗糙/虽然稀疏。
一些示例代码(来自mechanize网站)给你一个想法:
import mechanize
br = mechanize.Browser()
br.open("http://www.example.com/")
# follow second link with element text matching regular expression
html_response = br.follow_link(text_regex=r"cheese\s*shop", nr=1)
print br.title()
print html_response
BeautifulSoup 允许非常轻松地解析html内容(您可以使用mechanize获取),并支持正则表达式。
一些示例代码:
from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup(html_response)
rows = soup.findAll('tr')
for r in rows[2:]: #ignore first two rows
cols = r.findAll('td')
print cols[0].renderContents().strip() #print content of first column
因此,上面的这10行几乎可以复制粘贴,以便打印网站上每个表行第一列的内容。
答案 1 :(得分:4)
这里确实没有好的解决方案。你是对的,因为你怀疑Python可能是最好的开始方式,因为它非常强大地支持正则表达式。
为了实现这样的目标,SEO(搜索引擎优化)的强大知识将有所帮助,因为有效地优化搜索引擎的网页会告诉您搜索引擎的行为方式。我会从像SEOMoz这样的网站开始。
就识别“关于我们”页面而言,您只有两个选项:
a)对于每个页面,请获取about us页面的链接并将其提供给您的抓取工具。
b)解析某些关键字的页面的所有链接,例如“关于我们”,“关于”“了解更多”等等。
在使用选项b时,要小心,因为你可能陷入无限循环,因为网站会多次链接到同一页面,特别是如果链接在页眉或页脚中,页面甚至可以链接回自身。为了避免这种情况,您需要创建一个访问过的链接列表,并确保不要重新访问它们。
最后,我建议让您的抓取工具尊重robot.txt
文件中的说明,并且最好不要关注标记为rel="nofollow"
的链接,因为这些链接主要用于外部链接。再次,通过阅读SEO来学习这一点和更多。
此致
答案 2 :(得分:3)
答案 3 :(得分:3)
Python ==> Curl< - 爬虫的最佳实现
以下代码可以在一台漂亮的服务器上在300秒内抓取10,000个页面。
#! /usr/bin/env python
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
# $Id: retriever-multi.py,v 1.29 2005/07/28 11:04:13 mfx Exp $
#
# Usage: python retriever-multi.py <file with URLs to fetch> [<# of
# concurrent connections>]
#
import sys
import pycurl
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
except ImportError:
pass
# Get args
num_conn = 10
try:
if sys.argv[1] == "-":
urls = sys.stdin.readlines()
else:
urls = open(sys.argv[1]).readlines()
if len(sys.argv) >= 3:
num_conn = int(sys.argv[2])
except:
print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
raise SystemExit
# Make a queue with (url, filename) tuples
queue = []
for url in urls:
url = url.strip()
if not url or url[0] == "#":
continue
filename = "doc_%03d.dat" % (len(queue) + 1)
queue.append((url, filename))
# Check args
assert queue, "no URLs given"
num_urls = len(queue)
num_conn = min(num_conn, num_urls)
assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"
# Pre-allocate a list of curl objects
m = pycurl.CurlMulti()
m.handles = []
for i in range(num_conn):
c = pycurl.Curl()
c.fp = None
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(pycurl.MAXREDIRS, 5)
c.setopt(pycurl.CONNECTTIMEOUT, 30)
c.setopt(pycurl.TIMEOUT, 300)
c.setopt(pycurl.NOSIGNAL, 1)
m.handles.append(c)
# Main loop
freelist = m.handles[:]
num_processed = 0
while num_processed < num_urls:
# If there is an url to process and a free curl object, add to multi stack
while queue and freelist:
url, filename = queue.pop(0)
c = freelist.pop()
c.fp = open(filename, "wb")
c.setopt(pycurl.URL, url)
c.setopt(pycurl.WRITEDATA, c.fp)
m.add_handle(c)
# store some info
c.filename = filename
c.url = url
# Run the internal curl state machine for the multi stack
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
# Check for curl objects which have terminated, and add them to the freelist
while 1:
num_q, ok_list, err_list = m.info_read()
for c in ok_list:
c.fp.close()
c.fp = None
m.remove_handle(c)
print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL)
freelist.append(c)
for c, errno, errmsg in err_list:
c.fp.close()
c.fp = None
m.remove_handle(c)
print "Failed: ", c.filename, c.url, errno, errmsg
freelist.append(c)
num_processed = num_processed + len(ok_list) + len(err_list)
if num_q == 0:
break
# Currently no more I/O is pending, could do something in the meantime
# (display a progress bar, etc.).
# We just call select() to sleep until some more data is available.
m.select(1.0)
# Cleanup
for c in m.handles:
if c.fp is not None:
c.fp.close()
c.fp = None
c.close()
m.close()
答案 4 :(得分:2)
如果您要填充爬虫(需要特定于Java):
其他一些东西。
这并不困难,但有很多繁琐的边缘情况(例如重定向,检测编码(结帐Tika))。
有关更多基本要求,您可以使用wget。 Heretrix是另一种选择,但还有另一个需要学习的框架。
识别关于我们页面可以使用各种启发式方法完成:
如果你想更加量化它,你可以使用机器学习和分类器(可能是贝叶斯)。
保存首页显然更容易,但首页重定向(有时到不同的域,通常在HTML元重定向标记甚至JS中实现)非常常见,因此您需要处理此问题。
答案 5 :(得分:1)
Heritrix有一个陡峭的学习曲线,但可以配置为只有主页,以及“看起来像”(使用正则表达式过滤器)页面的页面将被抓取
更多开源Java(网络)抓取工具:http://java-source.net/open-source/crawlers