竞争定价的网络爬虫

5
我正在考虑编写一个应用程序,伪追踪竞争对手的网站,以确保我们的价格具有竞争力等。我考虑可能使用谷歌购物搜索API,但我觉得它可能缺乏灵活性,并且并非所有竞争对手都被完全列出或定期更新。
我的问题是,用基于PHP的网络爬虫从哪里开始?我显然希望爬虫尊重(即使是我们的竞争对手),所以它将遵守robots.txt和节流。(为了公平起见,我甚至认为我会将其托管在第三方服务器上,并让它爬行我们的网站以展示没有偏见。)我通过谷歌搜寻了一下,但我找不到任何成熟的软件包 - 只有一些标记为beta或alpha的糟糕的sourceforge脚本,尽管它们已经超过一年没有维护。
寻找想法或建议。 谢谢

你有没有研究过亚马逊网络服务API? - dqhendricks
1
@dqhendricks,我显然听说过AWS,但你是在建议使用它们的计算能力吗?还是他们有一个我不知道的爬虫API? - Brandon0
我建议您可以循环遍历自己的产品,然后通过亚马逊API查找每个产品所列出的价格。 - dqhendricks
1
@dqhendricks 亚马逊遇到了与 Google Shopping API 相同的问题 - 很少有我们的竞争对手在那里列出,而那些列出的也不一定经常更新其数据源。 - Brandon0
2个回答

1
一个爬虫本身并不复杂。只需加载网站,然后评估并跟踪找到的链接。
为了友好起见,你可以为每个计划抓取的网站定制一个爬虫。换句话说,选择一个网站,了解其结构,根据该结构编写获取请求和HTML解析的代码。然后,为其他网站重复这个过程。
如果他们使用的是常见的购物车软件(这里任何事情都有可能),那么显然可以进行一些复用。
在爬行时,你可能希望在非高峰时段访问他们的网站(这只是一个猜测)。此外,不要以每秒500个请求的速度执行。要大幅降低速度。
还有一个可选的做法是与这些其他网站联系,看看他们是否愿意参与直接数据共享。理想情况下,每个人都应该有一个产品的RSS订阅源。
当然,取决于你的销售对象,这可能被视为价格操纵...所以要谨慎行事。

竞争非常激烈,所以我不想直接向他们寻求帮助,但是我会尽可能利用每个站点的实时信息源。你说得对,对于每个网站都要建立一个定制爬虫(或者至少设置特定于该网站的规则)。我应该能够将链接限制在某些DOM节点上,这样就不会浪费时间爬取它们的非购物页面了。 - Brandon0

0

如果你只是寻找一个高效的爬虫,你可以使用这个... 这个爬虫可以在一个不错的服务器上在300秒内爬取大约10,000个网页。这个爬虫是用Python编写的,PHP也有类似的curl实现,但需要注意的是PHP不支持多线程,而多线程是考虑高效爬虫时一个重要的方面。

#! /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()

如果您正在寻找完整的价格比较系统,实际上您正在寻找一个定制的复杂网络项目。如果您找到了,请在此处分享链接;否则,如果您有兴趣进行自由职业工作,可以与我联系 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接