scrapy 中的 ItemLoader
優(yōu)點(diǎn)
ItemLoader最大的好處是作為一個容器糟红,可以多個spider復(fù)用提取規(guī)則恋捆。
可以把規(guī)則動態(tài)添加栅螟,因?yàn)橐?guī)則可以放入數(shù)據(jù)庫或者文件中幅疼。
ItemLoader不用考慮是否為空凹嘲,是否是0的值。
初步
在spider中
from scrapy.loader import ItemLoader
# 通過 ItemLoader 加載 item
item_loader = ItemLoader(item=JobBoleArticleItem(), response=response)
item_loader.add_css("title", ".entry-header h1::text")
# item_loader.add_xpath()
item_loader.add_value("url", response.url)
item_loader.add_value("front_image_url", get_md(response.url))
item_loader.add_css("create_date", ".entry-meta-hide-on-mobile::text")
item_loader.add_value("front_image_url", [front_image_url])
item_loader.add_css("praise_nums", "div.post-adds h10::text")
item_loader.add_css("fav_nums", ".bookmark-btn::text")
item_loader.add_css("comment_nums", "a[href='#article-comment'] span::text")
item_loader.add_css("tags", "p.entry-meta-hide-on-mobile a::text")
item_loader.add_css("content", ".entry")
article_item = item_loader.load_item()
問題:
-
article_item
里面的_value
的值都是list - 帶了空格的文字內(nèi)容悔叽,都要進(jìn)行正則表達(dá)式處理莱衩。
解決方法: input_processor=MapCompose
在items.py中解決。
值傳入時娇澎,進(jìn)行預(yù)處理笨蚁。
from scrapy.loader.processors import MapCompose
可以在item傳入值預(yù)處理的時候,連續(xù)調(diào)用兩個函數(shù)進(jìn)行處理趟庄。
例子:string拼接
只調(diào)用一個匿名函數(shù)赚窃,就在title后面加上了-jobbole
。
class JobBoleArticleItem(scrapy.Item):
title = scrapy.Field(
# input_processor = MapCompose(add_jobbole)
input_processor = MapCompose(lambda x:x+"-jobble")
調(diào)用兩個函數(shù)的例子岔激。同時加上了-jobbole
和-bobby
。
def add_jobbole(value):
return value + "-bobby"
class JobBoleArticleItem(scrapy.Item):
title = scrapy.Field(
# input_processor = MapCompose(add_jobbole)
input_processor = MapCompose(lambda x:x+"-jobble", add_jobbole)
)
例子:string轉(zhuǎn)化成date
def date_convert(value):
try:
create_date = datetime.datetime.strptime(value, "%Y/%m/%d").date()
except Exception as e:
create_date = datetime.datetime.now().date()
return create_date
class JobBoleArticleItem(scrapy.Item):
create_date = scrapy.Field(
input_processor = MapCompose(date_convert)
)
數(shù)組中提取值:TakeFirst
from scrapy.loader.processors import TakeFirst
class JobBoleArticleItem(scrapy.Item):
create_date = scrapy.Field(
input_processor = MapCompose(date_convert),
output_processor = TakeFirst()
)
自定義 ItemLoader
時間一次性TakeFirst
是掰。
from scrapy.loader import ItemLoader
繼承ItemLoader虑鼎,把原來的default_output_processor
替換掉
class ArticleItemLoader(ItemLoader):
# 自定義 itemloader
default_output_processor = TakeFirst()
把TakeFirst()
刪除掉。
class JobBoleArticleItem(scrapy.Item):
title = scrapy.Field(
# input_processor = MapCompose(add_jobbole)
input_processor = MapCompose(lambda x:x+"-jobble", add_jobbole)
)
create_date = scrapy.Field(
input_processor = MapCompose(date_convert),
# output_processor = TakeFirst()
)
在spider中键痛,
from ArticleSpider.items import JobBoleArticleItem, ArticleItemLoader
在spider中實(shí)例化的時候炫彩,使用ArticleItemLoader
。
item_loader = ArticleItemLoader(item=JobBoleArticleItem(), response=response)
正則提取三個item中的數(shù)字
import re
def get_nums(value):
match_re = re.match(".*?(\d+).*", value)
if match_re:
nums = int(match_re.group(1))
else:
nums = 0
return nums
class JobBoleArticleItem(scrapy.Item):
#...
praise_nums = scrapy.Field(
input_processor=MapCompose(get_nums),
)
comment_nums = scrapy.Field(
input_processor=MapCompose(get_nums),
)
fav_nums = scrapy.Field(
input_processor=MapCompose(get_nums),
)
最后得到三個變量為數(shù)字絮短。
對 tags 進(jìn)行 join
from scrapy.loader.processors import Join
class JobBoleArticleItem(scrapy.Item):
#...
tags = scrapy.Field(
output_processor=Join(",")
)
tag中的評論幾個字要去掉
def remove_comment_tags(value):
# 去掉 tags 中提取的評論
if "評論" in value:
return ""
else:
return value
class JobBoleArticleItem(scrapy.Item):
tags = scrapy.Field(
input_processor = MapCompose(remove_comment_tags),
output_processor=Join(",")
)
front-image-url 變成 list
def return_value(value):
return value
front_image_url = scrapy.Field(
output_processor=MapCompose(return_value)
)
可以覆蓋掉原來的
default_output_processor = TakeFirst()
同時保持原來的值江兢。原來就是一個list,要原封不動的傳遞出去丁频。就不要讓default的output_processor 去 TakeFirst()杉允。
但是sql中要取出 list 中的值。
另外在pipeline中席里,要對item中是否有 front_image_url進(jìn)行判斷叔磷。
class ArticleImagePipeline(ImagesPipeline):
def item_completed(self, results, item, info):
if "front_image_url" in item:
for ok, value in results:
image_file_path = value["path"]
item["front_image_path"] = image_file_path
return item