使用 Scrapy 清理数据
Cleaning data scraped using Scrapy
我最近开始使用 Scrapy 并尝试清理一些我已抓取并想导出为 CSV 的数据,即以下三个示例:
- 示例 1 – 删除特定文本
- 示例 2 – removing/replacing 不需要的字符
- 示例 3 – 拆分逗号分隔的文本
示例 1 数据如下:
Text I want,Text I don’t want
使用以下代码:
'Scraped 1': response.xpath('//div/div/div/h1/span/text()').extract()
示例 2 数据如下所示:
 - but I want to change this to £
使用以下代码:
' Scraped 2': response.xpath('//html/body/div/div/section/div/form/div/div/em/text()').extract()
示例 3 数据如下所示:
Item 1,Item 2,Item 3,Item 4,Item 4,Item5 – ultimately I want to split
this into separate columns in a CSV file
使用以下代码:
' Scraped 3': response.xpath('//div/div/div/ul/li/p/text()').extract()
我试过使用 str.replace()
,但似乎无法正常工作,例如:
'Scraped 1': response.xpath('//div/div/div/h1/span/text()').extract((str.replace(",Text I don't want","")
)
我正在调查此事,但如果有人能指出正确的方向,我将不胜感激!
代码如下:
import scrapy
from scrapy.loader import ItemLoader
from tutorial.items import Product
class QuotesSpider(scrapy.Spider):
name = "quotes_product"
start_urls = [
'http://www.unitestudents.com/',
]
# Step 1
def parse(self, response):
for city in response.xpath('//select[@id="frm_homeSelect_city"]/option[not(contains(text(),"Select your city"))]/text()').extract(): # Select all cities listed in the select (exclude the "Select your city" option)
yield scrapy.Request(response.urljoin("/"+city), callback=self.parse_citypage)
# Step 2
def parse_citypage(self, response):
for url in response.xpath('//div[@class="property-header"]/h3/span/a/@href').extract(): #Select for each property the url
yield scrapy.Request(response.urljoin(url), callback=self.parse_unitpage)
# Step 3
def parse_unitpage(self, response):
for final in response.xpath('//div/div/div[@class="content__btn"]/a/@href').extract(): #Select final page for data scrape
yield scrapy.Request(response.urljoin(final), callback=self.parse_final)
#Step 4
def parse_final(self, response):
unitTypes = response.xpath('//html/body/div').extract()
for unitType in unitTypes: # There can be multiple unit types so we yield an item for each unit type we can find.
l = ItemLoader(item=Product(), response=response)
l.add_xpath('area_name', '//div/ul/li/a/span/text()')
l.add_xpath('type', '//div/div/div/h1/span/text()')
l.add_xpath('period', '/html/body/div/div/section/div/form/h4/span/text()')
l.add_xpath('duration_weekly', '//html/body/div/div/section/div/form/div/div/em/text()')
l.add_xpath('guide_total', '//html/body/div/div/section/div/form/div/div/p/text()')
l.add_xpath('amenities','//div/div/div/ul/li/p/text()')
return l.load_item()
但是,我得到以下信息?
value = self.item.fields[field_name].get(key, default)
KeyError: 'type'
如果您提供蜘蛛和项目定义,提供更具体的答案会容易得多。以下是一些通用准则。
如果您想保持模块化并遵循 Scrapy 建议的项目架构和关注点分离,您应该清理并准备数据以通过 Item Loaders with input and output processors 进一步导出。
对于前两个示例,MapCompose
看起来很合适。
你对 str.replace
的想法是正确的,尽管我建议使用 Python 're' 正则表达式库,因为它更强大。文档是一流的,您可以在那里找到一些有用的代码示例。
我对scrapy库不熟悉,但它看起来像.extract()
returns一个字符串列表。如果你想使用 str.replace
或其中一个正则表达式函数来转换它们,你将需要使用列表理解:
'Selector 1': [ x.replace('A', 'B') for x in response.xpath('...').extract() ]
编辑:关于单独的列——如果数据已经用逗号分隔,只需将其直接写入文件即可!如果你想拆分逗号分隔的数据做一些转换,你可以像这样使用str.split
:
"A,B,C".split(",") # returns [ "A", "B", "C" ]
在这种情况下,从 .extract()
返回的数据将是逗号分隔字符串的列表。如果你使用上面的列表理解,你最终会得到一个列表的列表。
如果您想要比在每个逗号上拆分更复杂的东西,您可以使用 python 的 csv 库。
我最近开始使用 Scrapy 并尝试清理一些我已抓取并想导出为 CSV 的数据,即以下三个示例:
- 示例 1 – 删除特定文本
- 示例 2 – removing/replacing 不需要的字符
- 示例 3 – 拆分逗号分隔的文本
示例 1 数据如下:
Text I want,Text I don’t want
使用以下代码:
'Scraped 1': response.xpath('//div/div/div/h1/span/text()').extract()
示例 2 数据如下所示:
 - but I want to change this to £
使用以下代码:
' Scraped 2': response.xpath('//html/body/div/div/section/div/form/div/div/em/text()').extract()
示例 3 数据如下所示:
Item 1,Item 2,Item 3,Item 4,Item 4,Item5 – ultimately I want to split this into separate columns in a CSV file
使用以下代码:
' Scraped 3': response.xpath('//div/div/div/ul/li/p/text()').extract()
我试过使用 str.replace()
,但似乎无法正常工作,例如:
'Scraped 1': response.xpath('//div/div/div/h1/span/text()').extract((str.replace(",Text I don't want","")
)
我正在调查此事,但如果有人能指出正确的方向,我将不胜感激!
代码如下:
import scrapy
from scrapy.loader import ItemLoader
from tutorial.items import Product
class QuotesSpider(scrapy.Spider):
name = "quotes_product"
start_urls = [
'http://www.unitestudents.com/',
]
# Step 1
def parse(self, response):
for city in response.xpath('//select[@id="frm_homeSelect_city"]/option[not(contains(text(),"Select your city"))]/text()').extract(): # Select all cities listed in the select (exclude the "Select your city" option)
yield scrapy.Request(response.urljoin("/"+city), callback=self.parse_citypage)
# Step 2
def parse_citypage(self, response):
for url in response.xpath('//div[@class="property-header"]/h3/span/a/@href').extract(): #Select for each property the url
yield scrapy.Request(response.urljoin(url), callback=self.parse_unitpage)
# Step 3
def parse_unitpage(self, response):
for final in response.xpath('//div/div/div[@class="content__btn"]/a/@href').extract(): #Select final page for data scrape
yield scrapy.Request(response.urljoin(final), callback=self.parse_final)
#Step 4
def parse_final(self, response):
unitTypes = response.xpath('//html/body/div').extract()
for unitType in unitTypes: # There can be multiple unit types so we yield an item for each unit type we can find.
l = ItemLoader(item=Product(), response=response)
l.add_xpath('area_name', '//div/ul/li/a/span/text()')
l.add_xpath('type', '//div/div/div/h1/span/text()')
l.add_xpath('period', '/html/body/div/div/section/div/form/h4/span/text()')
l.add_xpath('duration_weekly', '//html/body/div/div/section/div/form/div/div/em/text()')
l.add_xpath('guide_total', '//html/body/div/div/section/div/form/div/div/p/text()')
l.add_xpath('amenities','//div/div/div/ul/li/p/text()')
return l.load_item()
但是,我得到以下信息?
value = self.item.fields[field_name].get(key, default)
KeyError: 'type'
如果您提供蜘蛛和项目定义,提供更具体的答案会容易得多。以下是一些通用准则。
如果您想保持模块化并遵循 Scrapy 建议的项目架构和关注点分离,您应该清理并准备数据以通过 Item Loaders with input and output processors 进一步导出。
对于前两个示例,MapCompose
看起来很合适。
你对 str.replace
的想法是正确的,尽管我建议使用 Python 're' 正则表达式库,因为它更强大。文档是一流的,您可以在那里找到一些有用的代码示例。
我对scrapy库不熟悉,但它看起来像.extract()
returns一个字符串列表。如果你想使用 str.replace
或其中一个正则表达式函数来转换它们,你将需要使用列表理解:
'Selector 1': [ x.replace('A', 'B') for x in response.xpath('...').extract() ]
编辑:关于单独的列——如果数据已经用逗号分隔,只需将其直接写入文件即可!如果你想拆分逗号分隔的数据做一些转换,你可以像这样使用str.split
:
"A,B,C".split(",") # returns [ "A", "B", "C" ]
在这种情况下,从 .extract()
返回的数据将是逗号分隔字符串的列表。如果你使用上面的列表理解,你最终会得到一个列表的列表。
如果您想要比在每个逗号上拆分更复杂的东西,您可以使用 python 的 csv 库。