我对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
答案 0 :(得分:1)
Scrapy已extensive documentation,the tutorial是一个很好的介绍。
它建立在Twisted之上,所以你必须考虑异步请求和响应,这与你通常使用python-requests和BS4做的完全不同。发出HTTP请求时,python-requests会阻塞您的线程。 Scrapy没有,它可以让你处理响应,而其他请求可能是通过网络。
您可以在scrapy回调中使用BS4(例如在您的parse_items
方法中)。
你是对的,Scrapy会在其输出中每行输出1个项目。它不会对URL进行任何重复数据删除,因为项目只是Scrapy的项目。它们碰巧包含您的案例中的URL。 Scrapy不会根据项目的内容对项目进行重复数据删除。您必须指示它这样做(例如item pipeline)
至于link_url
和link_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