Python 在scrapy中有多个请求时存储项目
我有一个项对象,我需要从方法phoneParse中取出该对象,并将其值与我已经加载的其他值一起加载 我试图从回调函数中获取电话号码,并在生成json或csv文件时以这种方式将其添加到加载程序中Python 在scrapy中有多个请求时存储项目,python,web-scraping,scrapy,Python,Web Scraping,Scrapy,我有一个项对象,我需要从方法phoneParse中取出该对象,并将其值与我已经加载的其他值一起加载 我试图从回调函数中获取电话号码,并在生成json或csv文件时以这种方式将其添加到加载程序中 loader.add_css("features", '.offer-features__item::text') loader.add_value('url', response.url) 以及数字的数据 我如何实现这样的功能 import scrapy import time import json
loader.add_css("features", '.offer-features__item::text')
loader.add_value('url', response.url)
以及数字的数据
我如何实现这样的功能
import scrapy
import time
import json
from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose
from scrapy.shell import inspect_response
from otomoto.items import OtomotoItem
def filter_out_array(x):
x = x.strip()
return None if x == '' else x
class OtomotoCarLoader(ItemLoader):
default_output_processor = TakeFirst()
features_out = MapCompose(filter_out_array)
class OtomotoSpider(scrapy.Spider):
name = 'otomoto'
start_urls = ['https://www.otomoto.pl/osobowe/']
def parse(self, response):
for car_page in response.css('.offer-title__link::attr(href)'):
yield response.follow(car_page, self.parse_car_page)
for next_page in response.css('.next.abs a::attr(href)'):
yield response.follow(next_page, self.parse)
########################## the function added to get the phone number ################
def parse_number(self, response):
#raw_data = response.url.body
#for params in raw_data:
number_id = response.xpath('//a[@data-path="multi_phone"]/@data-id').extract()
print("NUMBER", number_id)
number_id = list(dict.fromkeys(number_id))
#number_id = response.css('a::attr(data-id)' and 'a::attrdata-path="multi_phone")
print("NUMBER", number_id)
return number_id
#loader.add('number', number)
################################################################################
def phoneParse(self, response):
print("Res",response)
item = response.xpath('//p/text()').extract()
print(type(item))
print(item)
# HERE YOU NEED TO ITERATE IF YOU NEED ALL NUMBERS... but i think mostly they are the same, sometimes there are 2
json_acceptable_string = item[0].replace("'", "\"")
number_item_dict = json.loads(json_acceptable_string)
print("RES2",number_item_dict["value"].replace(" ","")) # THERE IT IS AS STRING
time.sleep(10)
return item
def parse_car_page(self, response):
number_id = self.parse_number(response)
for id in number_id:
phone_url = "https://www.otomoto.pl/ajax/misc/contact/multi_phone/" + id + '/0/'
print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA URL : "+phone_url)
request = scrapy.Request(phone_url, callback=self.phoneParse)
print(request)
yield request
#number = response.body
#print('NUMBER',number)
#<span class="objectBox objectBox-string">"725 169 377"</span>
#exit()
property_list_map = {
'Marka pojazdu': 'brand',
'Model pojazdu': 'model',
'Rok produkcji': 'year',
}
loader = OtomotoCarLoader(OtomotoItem(), response=response)
for params in response.css('.offer-params__item'):
property_name = params.css(
'.offer-params__label::text').extract_first().strip()
if property_name in property_list_map:
css = params.css('div::text').extract_first().strip()
if css == '':
css = params.css('a::text').extract_first().strip()
loader.add_value(property_list_map[property_name], css)
loader.add_css('features', '.offer-features__item::text')
loader.add_value('url', response.url)
#loader.add_value('number', response.number)
yield loader.load_item()
import scrapy
导入时间
导入json
从scrapy.loader导入ItemLoader
从scrapy.loader.processors导入TakeFirst,MapCompose
从scrapy.shell导入检查\u响应
从otomoto.items导入OtomotoItem
def过滤器输出阵列(x):
x=x.条带()
如果x==''或x,则返回None
装载机类别(项目装载机):
默认输出处理器=TakeFirst()
features\u out=MapCompose(过滤器\u out\u数组)
蜘蛛类(刮痕蜘蛛):
名称='otomoto'
起始URL=['https://www.otomoto.pl/osobowe/']
def解析(自我,响应):
对于响应中的car_页面.css('.offer-title_链接::attr(href'):
屈服响应。跟随(car\u页面,self.parse\u car\u页面)
对于response.css('.next.abs a::attr(href')中的下一页:
生成响应。follow(下一页,self.parse)
##########################添加的用于获取电话号码的功能################
def解析_编号(自身、响应):
#原始数据=response.url.body
#对于原始数据中的参数:
number\u id=response.xpath('//a[@data path=“multi\u phone”]/@data id').extract()
打印(“编号”,编号\u id)
number\u id=列表(dict.fromkeys(number\u id))
#number\u id=response.css('a::attr(数据id)'和'a::attr data path=“multi\u phone”)
打印(“编号”,编号\u id)
返回编号\u id
#加载器。添加('number',number)
################################################################################
def phoneParse(自我,响应):
打印(“Res”,回复)
item=response.xpath(“//p/text()”).extract()
打印(类型(项目))
打印(项目)
#在这里,如果需要所有数字,您需要迭代。。。但我认为大多数情况下它们是一样的,有时有两个
json\u可接受\u字符串=项[0]。替换(“'”,“\”)
number\u item\u dict=json.load(json\u可接受的字符串)
打印(“RES2”,编号项目内容[“值])。替换(“,”)#它以字符串形式出现
时间。睡眠(10)
退货项目
def解析车页面(自我,响应):
number\u id=self.parse\u number(响应)
对于编号为\u id的id:
电话地址=”https://www.otomoto.pl/ajax/misc/contact/multi_phone/“+id+”/0/'
打印(“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
request=scrapy.request(电话\ url,callback=self.phoneParse)
打印(请求)
让步请求
#数字=响应。正文
#打印('数字',数字)
#"725 169 377"
#退出()
属性列表映射={
“Marka pojazdu”:品牌,
“模型pojazdu”:“模型”,
"韩国产品":"年",,
}
loader=OtomotoCarLoader(OtomotoItem(),response=response)
对于response.css('.offer-params__项')中的参数:
属性_name=params.css(
'.offer-params__标签::text').extract_first().strip()
如果属性列表映射中的属性名称:
css=params.css('div::text')。首先提取()
如果css='':
css=params.css('a::text')。首先提取()
loader.add_值(属性列表映射[属性名称],css)
loader.add_css('features','。offer-features__项::text')
loader.add_值('url',response.url)
#loader.add_值('number',response.number)
产量加载器。加载_项()
Scrapy
使用调度程序运行请求,所以当您使用Request()
时,它会将其放入队列,稍后加载页面(当它有空闲的工作人员时,请参见:),所以它不会直接运行,并且您无法从parsePhoto
到parse\u car\u页面
您必须将数据从parse\u car\u页面发送到parsePhoto
:
- 在
parse\u car\u页面中
解析页面上的所有数据
- 在
parse\u car\u页面中
使用Request(…,meta=…)
将这些数据(或loader
)发送到parsePhoto
yield scrapy.Request(phone_url, callback=self.phone_parse, meta={'loader': loader})
- 在
parsePhoto
中获取这些数据
loader = response.meta['loader']
- 在
parsePhoto
中,刮取数字并生成所有数据
顺便说一句:在meta=
中,几乎可以使用任何键-但有些键有特殊含义:
完整的工作代码
您可以将它放在一个文件中,运行pythonscript.py
,而无需创建项目。它将数据保存在output.csv
import scrapy
from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose
from scrapy.shell import inspect_response
import json
import time
class OtomotoItem(scrapy.Item):
brand = scrapy.Field()
model = scrapy.Field()
year = scrapy.Field()
url = scrapy.Field()
number = scrapy.Field()
features = scrapy.Field()
def filter_out_array(x):
x = x.strip()
return None if x == '' else x
class OtomotoCarLoader(ItemLoader):
default_output_processor = TakeFirst()
features_out = MapCompose(filter_out_array)
class OtomotoSpider(scrapy.Spider):
name = 'otomoto'
start_urls = ['https://www.otomoto.pl/osobowe/']
def parse(self, response):
for car_page in response.css('.offer-title__link::attr(href)'):
yield response.follow(car_page, self.parse_car_page)
for next_page in response.css('.next.abs a::attr(href)'):
yield response.follow(next_page, self.parse)
def parse_car_page(self, response):
loader = OtomotoCarLoader(OtomotoItem(), response=response)
property_list_map = {
'Marka pojazdu': 'brand',
'Model pojazdu': 'model',
'Rok produkcji': 'year',
}
for params in response.css('.offer-params__item'):
property_name = params.css('.offer-params__label::text').extract_first().strip()
if property_name in property_list_map:
css = params.css('div::text').extract_first().strip()
if css == '':
css = params.css('a::text').extract_first().strip()
loader.add_value(property_list_map[property_name], css)
loader.add_css('features', '.offer-features__item::text')
loader.add_value('url', response.url)
number_id = self.parse_number(response)
print('number_id:', len(number_id), '|', number_id)
for id in number_id:
phone_url = "https://www.otomoto.pl/ajax/misc/contact/multi_phone/" + id + '/0/'
# use `meta=` to send data to `photo_parse`
yield scrapy.Request(phone_url, callback=self.phone_parse, meta={'loader': loader})
def parse_number(self, response):
number_id = response.xpath('//a[@data-path="multi_phone"]/@data-id').extract()
print("NUMBER [before]:", number_id)
number_id = list(set(number_id)) # you can use `set()` to get unique values
print("NUMBER [after] :", number_id)
return number_id
def phone_parse(self, response):
print("[phone_parse] response:", response)
# get data from `parse_car_page`
loader = response.meta['loader']
item = response.xpath('//p/text()').extract()
print('[phone_parse] item:', type(item), item)
json_data = json.loads(item[0])
print('[phone_parse] json:', json_data)
number = json_data["value"].replace(" ","")
print("'[phone_parse] number:", number) # THERE IT IS AS STRING
# add new data to loader
loader.add_value('number', number)
yield loader.load_item()
# --- run without project and save in `output.csv` ---
from scrapy.crawler import CrawlerProcess
c = CrawlerProcess({
'USER_AGENT': 'Mozilla/5.0',
# save in file CSV, JSON or XML
'FEED_FORMAT': 'csv', # csv, json, xml
'FEED_URI': 'output.csv', #
})
c.crawl(OtomotoSpider)
c.start()
你有一个JSON对象,你想填充它,然后一旦完成了抓取,就产生它?我不知道你想做什么,但通常你可以使用for
-循环yield
inside-iefor number in list_of_numbers:yield{“number”:number}
您必须更好地描述问题。可能会显示一些示例数据和预期结果。hey@furas感谢您的回答。我编辑了我的原始anwser,试图退出回调函数并将号码添加到LoaderPlace。感谢您为这一响应投入的时间和精力。它清晰易懂顺便说一句:我在GitHub上保留了一些Stackoverflow中的示例:不同页面的示例和示例我一定会查看它们的。非常感谢much@Max有什么问题吗?我可以毫无问题地获得Szczegóły
,但不需要使用loader
使用loade.ad的项中的ds