2015-06-19 57 views
1

我对Scrapy感到惊讶和沮丧。看起来引擎盖下的功率太大了,使它成为一个非常陡峭的学习曲线。显然,Scrapy可以完成我自己编程所需的所有工作,但问题在于如何让它做我想做的事情。在Scrapy链接收获

现在,我正在写一个简单的链接收割机。我想导出两个文件:一个带有内部链接和链接文本,另一个带有外部链接和链接文本。

我一直在试图给我们-o file.csv命令,但它将每个页面url作为一个列表存储到一个单元中,并且它包含重复项。

另一种方法是在'parse'中编写我自己的代码并手动创建一个链接列表,然后在添加它们之前查看它们是否存在于列表中,然后手动解析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 
+0

你可以分享你的代码?它会帮助你通过一个解决方案引导你 –

+1

我建议使用请求和美丽4.我试过Scrapy和我也有同感,如果你想我可以拿出一个简单的指南 – taesu

+0

我加了码。我想你可能对请求和BS4是正确的。我已经有了我的爬虫工作,但被Scrapy所能做的一切吸引了。有了要求和BS4,我知道发生的一切。通过Scrapy,我觉得你将代码投入虚空,上帝知道会出现什么。 – pekasus

回答

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 
+0

它在请求中很简单!我在所有链接上使用urlparse,然后在'netloc'上运行if语句。 – pekasus

+1

请求>>任何其他http库 –

1

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

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

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

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

至于表示为您link_urllink_text领域列表中的URL,这是因为sel.xpath('//a/@href').extract()returns lists

Scrapy 1.0(即将发布)增加了一个.extract_first()方法,这将有助于你的情况。

+0

项目管道是我所做的教程中缺少的关键。你解释的方式更清晰。所以基本上管道是scrapy的'代码'部分。我试图在抓取工具中转储所有内容,但没有意识到它应该放在管道中。 – pekasus

+1

感谢您的反馈。我会看到更新有关管道的文档和教程。 Scrapy回调函数旨在从页面中提取项目。流水线是处理项目时的一种方法,一次处理一个项目(所以你可以保留'(url,text)'元组的set()',并且如果项目的值已经存在导出2个文件可能[有点棘手](http://doc.scrapy.org/en/1.0/topics/exporters.html),你可能会更好的事后分裂输出(你可以有一个在您的项目定义内部/外部领域,以帮助集团的联系。 –

+0

你解释这是越来越清晰,这是信息,我一直在努力寻找的类型。我读过的文档几次,但这些细节int/ext字段是一个好主意,我还想在每个内部页面上运行关键字分析,对title,h1等进行加权。我想这也是一个管道代码。 ,我会做一个'如果内部'的代码,执行关键字分析。这是更有意义的。感谢您的帮助。 – pekasus

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 
+0

这是有道理的。尽管这会打开它自己的蠕虫。这些项目在管道中时是否存储在内存中,或者存储在需要首先读取的文件中?它一次输出一个项目,还是整个列表? – pekasus

+0

@JoshuaMeyer它一次只能成为一个项目,并不是所有的东西都一次存储在内存中。由于所有事件都是异步发生的,物品管道方法被用作回调。他们通过刮刀进入管道,然后写入磁盘(如在jsonwriter示例中)是否有意义? –