链接在Scrapy中收获

时间:2015-06-19 15:11:01

标签: python scrapy

我对Scrapy感到惊讶和沮丧。看起来引擎盖下的功率太大,使其成为一个非常陡峭的学习曲线。显然,Scrapy可以做我以前用来编程的所有事情,但问题在于弄清楚如何让它做我想做的事。

目前,我正在编写一个简单的链接收集器。我想导出两个文件:一个包含内部链接和链接文本,另一个包含外部链接和链接文本。

我一直在尝试使用-o file.csv命令,但它将每个页面url作为列表整合到一个单元格中,并且它包含重复项。

我的替代方案是在解析'中编写自己的代码。并手动创建链接列表,并在添加链接之前检查它们是否存在于列表中,然后手动解析该URL以查看域内或外部域。

似乎Scrapy应该通过一些命令来做到这一点。是否有内置方法?

这是我正在使用的代码。我评论了标题部分bc我认为我需要为那些制作另一个项目对象。我暂时放弃了那部分。

    def parse_items(self, response):
    item = WebconnectItem()
    sel = Selector(response)
    items = []
#    item["title"] = sel.xpath('//title/text()').extract()
#    item["current_url"] = response.url
    item["link_url"] = sel.xpath('//a/@href').extract()
    item["link_text"] = sel.xpath('//a/text()').extract()
    items.append(item)
    return items

3 个答案:

答案 0 :(得分:1)

Scrapy已extensive documentationthe tutorial是一个很好的介绍。

它建立在Twisted之上,所以你必须考虑异步请求和响应,这与你通常使用python-requests和BS4做的完全不同。发出HTTP请求时,python-requests会阻塞您的线程。 Scrapy没有,它可以让你处理响应,而其他请求可能是通过网络。

您可以在scrapy回调中使用BS4(例如在您的parse_items方法中)。

你是对的,Scrapy会在其输出中每行输出1个项目。它不会对URL进行任何重复数据删除,因为项目只是Scrapy的项目。它们碰巧包含您的案例中的URL。 Scrapy不会根据项目的内容对项目进行重复数据删除。您必须指示它这样做(例如item pipeline

至于link_urllink_text字段中列为网址的网址,因为sel.xpath('//a/@href').extract() returns lists

Scrapy 1.0(即将发布)添加了.extract_first()方法,对您的情况有所帮助。

答案 1 :(得分:1)

因此,您对scrapy的看法基本上是准确的。非常强大,陡峭的学习曲线,但如果你可以超越那个部分有很多承诺。甚至还有一些像ScrapingHub这样可以处理旋转IP地址,保持工作运行等等的增值服务...

区别在于scrapy使用项目管道而不是传统模型。他们有很好的代码可以解决你所遇到的问题。任何结果处理都应该在这些项目管道中进行,而不是在刮刀本身中进行。文档是here,这是删除重复项并写入json的示例管道:

class DuplicatesPipeline(object):

    def __init__(self):
        self.ids_seen = set()

    def process_item(self, item, spider):
        if item['id'] in self.ids_seen:
            raise DropItem("Duplicate item found: %s" % item)
        else:
            self.ids_seen.add(item['id'])
            return item

class JsonWriterPipeline(object):

    def __init__(self):
        self.file = open('items.jl', 'wb')

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

答案 2 :(得分:0)

使用请求& BS4
请注意,它不是最佳解决方案,但它显示了如何使用请求和bs4来完成。
我的goto设置。

import requests
from bs4 import BeautifulSoup
URL = "http://www.cnn.com/"

# get request
r = requests.get(URL) 
# turn into bs instance
soup = BeautifulSoup(r.text) 
# get all links
links = soup.findAll('a')

internal_unique = []
external_unique = []
internal_links = []
external_links = []

for link in links:
    if 'ccn.com' in link['href'] or link['href'].startswith('/'):
        if link['href'] not in internal_unique:
            internal_links.append({'link':link['href'],'text':link.get_text()})
            internal_unique.append(link['href'])
    else:
        if link['href'] not in external_unique:
            external_links.append({'link':link['href'],'text':link.get_text()})
            external_unique.append(link['href'])
print internal_links
print external_links