- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
这是我的第一个 scrapy 项目——不可否认,这也是我使用 python 的第一个练习之一。我正在寻找一种方法来抓取多个子页面,将内容合并/附加到单个值,并将数据向后/向上传递到原始父页面。每个父页面的子页面数量也是可变的 - 它可能少至 1,但永远不会是 0(可能对错误处理有帮助?)。此外,子页面可以重复并重新出现,因为它们不是单亲所独有的。我已经设法将父页面元数据向下传递到相应的子页面,但在完成相反的过程中遇到了困难。
这是一个示例页面结构:
Top Level Domain
- Pagination/Index Page #1 (parse recipe links)
- Recipe #1 (select info & parse ingredient links)
- Ingredient #1 (select info)
- Ingredient #2 (select info)
- Ingredient #3 (select info)
- Recipe #2
- Ingredient #1
- Recipe #3
- Ingredient #1
- Ingredient #2
- Pagination/Index Page #2
- Recipe #N
- Ingredient #N
- ...
- Pagination/Index Page #3
- ... continued
我正在寻找的输出(每个食谱)如下所示:
{
"recipe_title": "Gin & Tonic",
"recipe_posted_date": "May 2, 2019",
"recipe_url": "www.XYZ.com/gandt.html",
"recipe_instructions": "<block of text here>",
"recipe_ingredients": ["gin", "tonic water", "lime wedge"],
"recipe_calorie_total": "135 calories",
"recipe_calorie_list": ["60 calories", "70 calories", "5 calories"]
}
我正在从相应的食谱页面中提取每种成分的 URL。我需要从每个成分页面中提取卡路里计数,将其与其他成分的卡路里计数合并,并理想地生成单个项目。由于单一成分并不专属于单一食谱,因此我需要能够在稍后的抓取过程中重新访问成分页面。
(注意 - 这不是真实的例子,因为卡路里数明显根据食谱所需的量而变化)
我发布的代码让我接近我正在寻找的东西,但我必须想象有一种更优雅的方法来解决问题。发布的代码成功地将食谱的元数据向下传递到成分级别,循环遍历成分并附加卡路里计数。由于信息是被传递下来的,所以我在成分层面上做出了让步,并创建了许多食谱重复项(每种成分一个),直到我循环使用最后一种成分。在此阶段,我希望添加成分索引号,以便我可以以某种方式保留每个食谱 URL 具有最大成分索引# 的记录。在我到达这一点之前,我想我应该向这里的专业人士寻求指导。
爬虫代码:
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from recipe_scraper.items import RecipeItem
class RecipeSpider(CrawlSpider):
name = 'Recipe'
allowed_domains = ['www.example.com']
start_urls = ['https://www.example.com/recipes/']
rules = (
Rule(
LinkExtractor(
allow=()
,restrict_css=('.pagination')
,unique=True
)
,callback='parse_index_page'
,follow=True
),
)
def parse_index_page(self, response):
print('Processing Index Page.. ' + response.url)
index_url = response.url
recipe_urls = response.css('.recipe > a::attr(href)').getall()
for a in recipe_urls:
request = scrapy.Request(a, callback=self.parse_recipe_page)
request.meta['index_url'] = index_url
yield request
def parse_recipe_page(self, response):
print('Processing Recipe Page.. ' + response.url)
Recipe_url = response.url
Recipe_title = response.css('.Recipe_title::text').extract()[0]
Recipe_posted_date = response.css('.Recipe_posted_date::text').extract()[0]
Recipe_instructions = response.css('.Recipe_instructions::text').extract()[0]
Recipe_ingredients = response.xpath('//ul[@class="ingredients"]//li[@class="ingredient"]/a/text()').getall()
Recipe_ingredient_urls = response.xpath('//ul[@class="ingredients"]//li[@class="ingredient"]/a/@href').getall()
Recipe_calorie_list_append = []
Recipe_calorie_list = []
Recipe_calorie_total = []
Recipe_item = RecipeItem()
Recipe_item['index_url'] = response.meta["index_url"]
Recipe_item['Recipe_url'] = Recipe_url
Recipe_item['Recipe_title'] = Recipe_title
Recipe_item['Recipe_posted_date'] = Recipe_posted_date
Recipe_item['Recipe_instructions'] = Recipe_instructions
Recipe_item['Recipe_ingredients'] = Recipe_ingredients
Recipe_item['Recipe_ingredient_urls'] = Recipe_ingredient_urls
Recipe_item['Recipe_ingredient_url_count'] = len(Recipe_ingredient_urls)
Recipe_calorie_list.clear()
Recipe_ingredient_url_index = 0
while Recipe_ingredient_url_index < len(Recipe_ingredient_urls):
ingredient_request = scrapy.Request(Recipe_ingredient_urls[Recipe_ingredient_url_index], callback=self.parse_ingredient_page, dont_filter=True)
ingredient_request.meta['Recipe_item'] = Recipe_item
ingredient_request.meta['Recipe_calorie_list'] = Recipe_calorie_list
yield ingredient_request
Recipe_calorie_list_append.append(Recipe_calorie_list)
Recipe_ingredient_url_index += 1
def parse_ingredient_page(self, response):
print('Processing Ingredient Page.. ' + response.url)
Recipe_item = response.meta['Recipe_item']
Recipe_calorie_list = response.meta["Recipe_calorie_list"]
ingredient_url = response.url
ingredient_calorie_total = response.css('div.calorie::text').getall()
Recipe_calorie_list.append(ingredient_calorie_total)
Recipe_item['Recipe_calorie_list'] = Recipe_calorie_list
yield Recipe_item
Recipe_calorie_list.clear()
事实上,我不太理想的输出如下(注意卡路里列表):
{
"recipe_title": "Gin & Tonic",
"recipe_posted_date": "May 2, 2019",
"recipe_url": "www.XYZ.com/gandt.html",
"recipe_instructions": "<block of text here>",
"recipe_ingredients": ["gin", "tonic water", "lime wedge"],
"recipe_calorie_total": [],
"recipe_calorie_list": ["60 calories"]
},
{
"recipe_title": "Gin & Tonic",
"recipe_posted_date": "May 2, 2019",
"recipe_url": "www.XYZ.com/gandt.html",
"recipe_instructions": "<block of text here>",
"recipe_ingredients": ["gin", "tonic water", "lime wedge"],
"recipe_calorie_total": [],
"recipe_calorie_list": ["60 calories", "70 calories"]
},
{
"recipe_title": "Gin & Tonic",
"recipe_posted_date": "May 2, 2019",
"recipe_url": "www.XYZ.com/gandt.html",
"recipe_instructions": "<block of text here>",
"recipe_ingredients": ["gin", "tonic water", "lime wedge"],
"recipe_calorie_total": [],
"recipe_calorie_list": ["60 calories", "70 calories", "5 calories"]
}
最佳答案
一种解决方案是分别抓取食谱和配料,作为不同的项目,然后在抓取完成后进行一些后处理,例如使用常规 Python,根据需要合并食谱和配料数据。这是最有效的解决方案。
或者,您可以从菜谱响应中提取成分 URL,而不是一次生成对所有成分的请求,您可以生成对第一种成分的请求,并将其余成分 URL 保存到新请求 meta
,以及食谱项目。收到成分响应后,您将所有需要的信息解析为 meta
并生成对下一个成分 URL 的新请求。当不再有成分 URL 时,您将生成完整的食谱项目。
例如:
def _handle_next_ingredient(self, recipe, ingredient_urls):
try:
return Request(
ingredient_urls.pop(),
callback=self.parse_ingredient,
meta={'recipe': recipe, 'ingredient_urls': ingredient_urls},
)
except IndexError:
return recipe
def parse_recipe(self, response):
recipe = {}, ingredient_urls = []
# [Extract needed data into recipe and ingredient URLs into ingredient_urls]
yield self._handle_next_ingredient(recipe, ingredient_urls)
def parse_ingredient(self, response):
recipe = response.meta['recipe']
# [Extend recipe with the information of this ingredient]
yield self._handle_next_ingredient(recipe, response.meta['ingredient_urls'])
但请注意,如果两个或多个食谱可以具有相同的成分 URL,则您必须将 dont_filter=True
添加到您的请求中,从而对相同成分重复多个请求。如果成分 URL 不是特定于配方的,请认真考虑第一个建议。
关于python - 如何解析多个子页面、合并/追加并向上传递到父级?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55960550/
在 Python 中,我可以附加到一个空数组,例如: >>> a = [] >>> a.append([1,2,3]) >>> a.append([1,2,3]) >>> a [[1, 2, 3],
我正在阅读(并慢慢尝试)在 php 中与 txt 文件交互的方法。我已经尝试过追加,它将数据添加到txt文件的末尾但是 a+ 与 a 有何不同 在 w3schools 中它说: 一个 append 。
我想执行一个非常简单的操作:合并两个形状文件。具体来说,我有美国每个州的人口普查区域形状文件,我想将它们合并到一个形状文件中。最终,我想获取组合的形状文件并在一组经纬度坐标上执行叠加,以确定我的坐标属
当我们使用 append 和 cut 运算符时会出现什么问题? append2([],L,L):-!. append2([H|T],L,[H|TL]):-append2(T,L,TL).
我有一个函数处理程序: function handler(data) { console.log(`1. ${data}`); } 我想在相同的范围内附加或重新定义,如下所示: let old
我目前正在使用很多这样的内容来重构应用程序: StringBuffer buff1 = new StringBuffer(""); buff1.append("some value A"); buff
我正在编写一些代码来对不同类型的啤酒进行一些计算。我有一个使用 GUI 的主类,并有一个 JTextArea 来打印输出。在主类中调用追加工作得很好,但是当我尝试从外部类调用追加来写入文本区域时...
我有一个像这样的 jquery block 。渲染 html 后,我看到 标签立即打开和关闭,同样的方式,立即打开和关闭。我在他的代码中做错了什么吗?有更好的方法来实现这个吗? 谢谢 $.each(f
我在尝试克隆父 div 然后将其直接附加到其自身下方时遇到一个问题。只要最后一个节点是,我的函数就可以正常工作如此选择: A B C 将导致 A A.1
我正在尝试在现有 td 末尾附加一个 td。下面是以下代码(我在 jqgrid 中执行)。 $("#list_toppager_center tr:first td:eq(7)").append("C
我正在尝试在 jQuery 中的以下追加方法上设置超时。我尝试过的所有操作都不断返回Uncaught SyntaxError:意外的标识符 这是我的代码: setTimeout("$('#us
我想用 c 打开一个文件,然后向其中添加一些内容并关闭它。我只是想知道 fopen 中的 a+ 自动导航到文件的最后一个字符。 最佳答案 是的。 为什么不尝试一下,或者阅读一下手册呢? 这里是:
在我的代码中,我有一个输入字段,它是一个循环的值。 用户在第一个字段中输入所需的值。 用户单击按钮/徽章(单击我添加项目符号)以附加到模式。 根据字段中的输入值显示带有项目符号数的模态框。 例如,如果
是否可以使用 QUrlQuery 在不对 url 进行 strip 化的情况下 append 数据? 使用下面的代码将删除“?”之后的所有内容和结果是: https://foobar.com/Info
好吧,我正在为 iPhone 制作一个简单的聊天应用程序,我很幸运,它运行良好并且看起来很棒但是我有一些问题,一个这样的问题是我向用户显示富文本的方式.. 目前我有一个荒谬的系统,它是这样工作的 {发
在 C# 中格式化我做的字符串: string a = String.Format("/blah/blah/{0}_{1}/blah.html", int1, int2) 在Python中,它会自动将
我有一个 300 万行的 .txt 文件。该文件包含如下所示的数据: # RSYNC: 0 1 1 0 512 0 #$SOA 5m localhost. hostmaster.localhost.
我有一个问题。可以删除使用 javascript 附加添加的元素? 当我尝试删除添加的跨度时,什么也没有发生。 像这样: $(document).ready(function(){ $('#
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
到目前为止这是我的代码,我想做的是说用户输入 1 2 3 然后按 -1,他或她将被要求输入另一组数字,比如 9 8 7,我的程序是什么假设要做的是将它们显示为 1 2 3 9 8 7,而是像这样显示它
我是一名优秀的程序员,十分优秀!