我是新手scrapy
,我的任务很简单:
对于给定的电子商务网站:
抓取所有网站页面
寻找产品页面
如果URL指向产品页面
创建一个项目
处理项目以将其存储在数据库中
我创建了蜘蛛,但产品只是打印在一个简单的文件中.
我的问题是项目结构:如何在蜘蛛中使用物品以及如何将物品发送到管道?
我找不到使用项目和管道的项目的简单示例.
我有一个使用自定义的中间件和自定义管道检查和存储条目在一个Postgres数据库一个Scrapy项目.中间件看起来有点像这样:
class ExistingLinkCheckMiddleware(object): def __init__(self): ... open connection to database def process_request(self, request, spider): ... before each request check in the DB that the page hasn't been scraped before
管道看起来很相似:
class MachinelearningPipeline(object): def __init__(self): ... open connection to database def process_item(self, item, spider): ... save the item to the database
它运行正常,但是当蜘蛛完成时我无法找到干净地关闭这些数据库连接的方法,这让我感到烦恼.
有谁知道这是怎么做到的吗?
我有Scrapy(版本1.0.3)蜘蛛,其中我从网页中提取了一些数据,我也下载了文件,像这样(简化):
def extract_data(self, response):
title = response.xpath('//html/head/title/text()').extract()[0].strip()
my_item = MyItem()
my_item['title'] = title
file_url = response.xpath('...get url of file...')
file_urls = [file_url] # here there can be more urls, so I'm storing like a list
fi = FileItem()
fi['file_urls'] = file_urls
yield my_item
yield fi
Run Code Online (Sandbox Code Playgroud)
在pipelines.py中我只是重写FilePipeline来更改文件的名称:
from scrapy.pipelines.files import FilesPipeline
class CustomFilesPipeline(FilesPipeline):
def file_path(self, request, response=None, info=None):
filename = format_filename(request.url)
return filename
Run Code Online (Sandbox Code Playgroud)
在items.py我有:
class MyItem(scrapy.Item):
title = scrapy.Field()
class FileItem(scrapy.Item):
file_urls = scrapy.Field()
files = scrapy.Field()
Run Code Online (Sandbox Code Playgroud)
在settings.py我有:
ITEM_PIPELINES = { …
Run Code Online (Sandbox Code Playgroud) 我有以下Django模型。我不确定使用scrapy管道在Spider中扫描到Django中的数据库时,保存这些相互关联的对象的最佳方法是什么。似乎刮擦的管道仅用于处理一种“种类”的物料
class Parent(models.Model):
field1 = CharField()
class ParentX(models.Model):
field2 = CharField()
parent = models.OneToOneField(Parent, related_name = 'extra_properties')
class Child(models.Model):
field3 = CharField()
parent = models.ForeignKey(Parent, related_name='childs')
Run Code Online (Sandbox Code Playgroud)
# uses DjangoItem https://github.com/scrapy-plugins/scrapy-djangoitem
class ParentItem(DjangoItem):
django_model = Parent
class ParentXItem(DjangoItem):
django_model = ParentX
class ChildItem(DjangoItem):
django_model = Child
Run Code Online (Sandbox Code Playgroud)
class MySpider(scrapy.Spider):
name = "myspider"
allowed_domains = ["abc.com"]
start_urls = [
"http://www.example.com", # this page has ids of several Parent objects whose full details are in their individual pages
]
def parse(self, …
Run Code Online (Sandbox Code Playgroud) 我使用 Scrapy(又名 Twisted)和 Postgres 作为数据库。
在我之后,虽然我的连接似乎填满了,然后我的脚本被卡住了。我用这个查询检查了这个SELECT * FROM pg_stat_activity;
并读到它是因为 Postgres 没有连接池造成的。
我读过txpostgres和PGBouncer,遗憾的是 Bouncer 不是一个选项,我还能做些什么来避免这个问题?
到目前为止,我使用以下管道:
import psycopg2
from twisted.enterprise import adbapi
import logging
from datetime import datetime
import scrapy
from scrapy.exceptions import DropItem
class PostgreSQLPipeline(object):
""" PostgreSQL pipeline class """
def __init__(self, dbpool):
self.logger = logging.getLogger(__name__)
self.dbpool = dbpool
@classmethod
def from_settings(cls, settings):
dbargs = dict(
host=settings['POSTGRESQL_HOST'],
database=settings['POSTGRESQL_DATABASE'],
user=settings['POSTGRESQL_USER'],
password=settings['POSTGRESQL_PASSWORD'],
)
dbpool = adbapi.ConnectionPool('psycopg2', **dbargs)
return cls(dbpool)
def process_item(self, item, spider):
d …
Run Code Online (Sandbox Code Playgroud) 我只需要了解如何检测scrapy是否已保存以及蜘蛛中的项目?我正在从网站上获取项目,之后我正在获取该项目的评论.所以首先我必须保存项目,之后我会保存评论.但是当我在编写代码之后编写代码时,它会给我这个错误.
save() prohibited to prevent data loss due to unsaved related object ''.
这是我的代码
def parseProductComments(self, response):
name = response.css('h1.product-name::text').extract_first()
price = response.css('span[id=offering-price] > span::text').extract_first()
node = response.xpath("//script[contains(text(),'var utagData = ')]/text()")
data = node.re('= (\{.+\})')[0] #data = xpath.re(" = (\{.+\})")
data = json.loads(data)
barcode = data['product_barcode']
objectImages = []
for imageThumDiv in response.css('div[id=productThumbnailsCarousel]'):
images = imageThumDiv.xpath('img/@data-src').extract()
for image in images:
imageQuality = image.replace('/80/', '/500/')
objectImages.append(imageQuality)
company = Company.objects.get(pk=3)
comments = []
item = ProductItem(name=name, price=price, barcode=barcode, file_urls=objectImages, product_url=response.url,product_company=company, comments = …
Run Code Online (Sandbox Code Playgroud) 我目前正在完成一个Scrapy项目,但是我的pipelines.py
文件很长。
我注意到在我settings.py
的管道中显示如下(修剪掉):
ITEM_PIPELINES = {
'proj.pipelines.MutatorPipeline': 200,
'proj.pipelines.CalculatorPipeline': 300,
'proj.pipelines.SaveToFilePipeline': 500,
}
Run Code Online (Sandbox Code Playgroud)
我尝试了以下方法来纠正此问题。
1.)我创建了一个新的文件/文件夹,并尝试以相同的方式从管道中引用它。
Folder myPipelines/Test.py
的类名为,TestPipeline
然后在管道设置中引用为proj.myPipelines.Test.TestPipeline': 100,
。
这给我带来了错误。
然后我以为我可以导出模块并导入到当前模块中,pipelines.py
它将从中获得参考。我__init__.py
在myPipelines
目录中添加了一个空然后添加,from myPipelines.Test import TestPipeline
但是scrapy仍然引发错误...
Raise NameError("Module '%s' doesn't define any object named '%s'" % (module, name))
exceptions.NameError: Module 'proj.pipelines' doesn't define any object named 'TestPipeline'.
Run Code Online (Sandbox Code Playgroud)
提前谢谢了!
对于我scrapy项目我目前使用的FilesPipeline。下载的文件以其URL的SHA1哈希作为文件名存储。
[(True,
{'checksum': '2b00042f7481c7b056c4b410d28f33cf',
'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg',
'url': 'http://www.example.com/files/product1.pdf'}),
(False,
Failure(...))]
Run Code Online (Sandbox Code Playgroud)
如何使用自定义文件名存储文件?
在上面的示例中,我希望文件名为“ product1_0a79c461a4062ac383dc4fade7bc09f1384a3910.pdf”,因此我保持唯一性,但使文件名可见。
首先,我探索了pipelines.py
我的项目,但没有取得太大的成功。
import scrapy
from scrapy.pipelines.images import FilesPipeline
from scrapy.exceptions import DropItem
class MyFilesPipeline(FilesPipeline):
def file_path(self, request, response=None, info=None):
return request.meta.get('filename','')
def get_media_requests(self, item, info):
file_url = item['file_url']
meta = {'filename': item['name']}
yield Request(url=file_url, meta=meta)
Run Code Online (Sandbox Code Playgroud)
并在我的 settings.py
ITEM_PIPELINES = {
#'scrapy.pipelines.files.FilesPipeline': 300
'io_spider.pipelines.MyFilesPipeline': 200
}
Run Code Online (Sandbox Code Playgroud)
一个类似的问题已经被问,但它的目标图像,而不是文件。
任何帮助将不胜感激。
我是从moocs刮审查喜欢这一个
从那里我获得了所有课程的详细信息,每个评论本身有 5 个项目和另外 6 个项目。
这是我拥有的课程详细信息的代码:
def parse_reviews(self, response):
l = ItemLoader(item=MoocsItem(), response=response)
l.add_xpath('course_title', '//*[@class="course-header-ng__main-info__name__title"]//text()')
l.add_xpath('course_description', '//*[@class="course-info__description"]//p/text()')
l.add_xpath('course_instructors', '//*[@class="course-info__instructors__names"]//text()')
l.add_xpath('course_key_concepts', '//*[@class="key-concepts__labels"]//text()')
l.add_value('course_link', response.url)
return l.load_item()
Run Code Online (Sandbox Code Playgroud)
现在我想包括评论详细信息,每个评论另外 5 个项目。由于课程数据对于所有评论都是通用的,我想将其存储在不同的文件中,然后使用课程名称/ID 关联数据。
这是我用于评论项目的代码:
for review in response.xpath('//*[@class="review-body"]'):
review_body = review.xpath('.//div[@class="review-body__content"]//text()').extract()
course_stage = review.xpath('.//*[@class="review-body-info__course-stage--completed"]//text()').extract()
user_name = review.xpath('.//*[@class="review-body__username"]//text()').extract()
review_date = review.xpath('.//*[@itemprop="datePublished"]/@datetime').extract()
score = review.xpath('.//*[@class="sr-only"]//text()').extract()
Run Code Online (Sandbox Code Playgroud)
我尝试使用临时解决方案,返回每个案例的所有项目,但也不起作用:
def parse_reviews(self, response):
#print response.body
l = ItemLoader(item=MoocsItem(), response=response)
#l = MyItemLoader(selector=response)
l.add_xpath('course_title', '//*[@class="course-header-ng__main-info__name__title"]//text()')
l.add_xpath('course_description', '//*[@class="course-info__description"]//p/text()')
l.add_xpath('course_instructors', '//*[@class="course-info__instructors__names"]//text()')
l.add_xpath('course_key_concepts', '//*[@class="key-concepts__labels"]//text()')
l.add_value('course_link', response.url)
for review in response.xpath('//*[@class="review-body"]'):
l.add_xpath('review_body', './/div[@class="review-body__content"]//text()') …
Run Code Online (Sandbox Code Playgroud) 假设我有一个看似这样的刮取项目
{
name: "Foo",
country: "US",
url: "http://..."
}
Run Code Online (Sandbox Code Playgroud)
在管道中,我想对URL发出GET请求,并检查一些标题,如content_type和status.当标题不符合某些条件时,我想删除该项目.喜欢
class MyPipeline(object):
def process_item(self, item, spider):
request(item['url'], function(response) {
if (...) {
raise DropItem()
}
return item
}, function(error){
raise DropItem()
})
Run Code Online (Sandbox Code Playgroud)
使用管道不可能闻到这样的气味.你怎么看?任何想法如何实现这一目标?
蜘蛛:
import scrapy
import json
class StationSpider(scrapy.Spider):
name = 'station'
start_urls = ['http://...']
def parse(self, response):
jsonResponse = json.loads(response.body_as_unicode())
for station in jsonResponse:
yield station
Run Code Online (Sandbox Code Playgroud) scrapy-pipeline ×10
scrapy ×9
python ×8
django ×2
postgresql ×1
psycopg2 ×1
twisted ×1
web-scraping ×1