python scrapy 只拉第一行,但重复 table 中正确数量的项目
python scrapy only pulling first row but repeating for the correct amount of items in the table
如标题所说。我的 scrapy 代码似乎是 运行 正确的,只是它只拉出 table 的第一行并重复 table.
中的行数
import scrapy
class FightersSpider(scrapy.Spider):
name = "fighters"
start_urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
def start_requests(self):
urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response, **kwargs):
for fighter in response.xpath('//*[@class="b-statistics__table"]//tbody/tr'):
yield {
'first': fighter.xpath('//td[1]/a//text()').extract_first(),
'last': fighter.xpath('//td[2]/a//text()').extract_first(),
'nickname': fighter.xpath('//td[3]/a//text()').extract_first(),
'height': fighter.xpath('//td[4]//text()').extract_first().strip(),
'weight': fighter.xpath('//td[5]//text()').extract_first().strip(),
'reach': fighter.xpath('//td[6]//text()').extract_first().strip(),
'stance': fighter.xpath('//td[7]//text()').extract_first().strip(),
'wins': fighter.xpath('//td[8]//text()').extract_first().strip(),
'losses': fighter.xpath('//td[9]//text()').extract_first().strip(),
'draws': fighter.xpath('//td[10]//text()').extract_first().strip(),
}
如果我取出 _first
,它会提取所有数据,但将其放在同一个单元格中并以相同的方式重复。
first last nickname height weight reach stance wins losses
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
....
您必须使用 relative xpath
仅在 fighter
内搜索 - 它必须以 dot
开头
fighter.xpath('.//td[1]/a//text()')
没有 dot
它是 absolute xpath
并且它搜索所有 HTML 并且总是找到第一行。
但是你会遇到其他问题。
你得到了 table 中的所有行 - 甚至 header 没有 td
- 你必须跳过它。您可以使用 [1:]
对其进行切片
for fighter in response.xpath(...)[1:]:
最少的工作代码。
您可以将所有内容复制到文件并作为普通脚本启动它 python script.py
而无需在 scrapy
中创建项目
import scrapy
class FightersSpider(scrapy.Spider):
name = "fighters"
start_urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
def start_requests(self):
urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response, **kwargs):
for fighter in response.xpath('//*[@class="b-statistics__table"]//tbody/tr')[1:]:
print(fighter.xpath('.//td[4]'))
yield {
'first': fighter.xpath('.//td[1]/a//text()').extract_first(),
'last': fighter.xpath('.//td[2]/a//text()').extract_first(),
'nickname': fighter.xpath('.//td[3]/a//text()').extract_first(),
'height': fighter.xpath('.//td[4]//text()').extract_first().strip(),
'weight': fighter.xpath('.//td[5]//text()').extract_first().strip(),
'reach': fighter.xpath('.//td[6]//text()').extract_first().strip(),
'stance': fighter.xpath('.//td[7]//text()').extract_first().strip(),
'wins': fighter.xpath('.//td[8]//text()').extract_first().strip(),
'losses': fighter.xpath('.//td[9]//text()').extract_first().strip(),
'draws': fighter.xpath('.//td[10]//text()').extract_first().strip(),
}
# --- 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
'FEEDS': {'output.csv': {'format': 'csv'}}, # new in 2.1
})
c.crawl(FightersSpider)
c.start()
如标题所说。我的 scrapy 代码似乎是 运行 正确的,只是它只拉出 table 的第一行并重复 table.
中的行数import scrapy
class FightersSpider(scrapy.Spider):
name = "fighters"
start_urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
def start_requests(self):
urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response, **kwargs):
for fighter in response.xpath('//*[@class="b-statistics__table"]//tbody/tr'):
yield {
'first': fighter.xpath('//td[1]/a//text()').extract_first(),
'last': fighter.xpath('//td[2]/a//text()').extract_first(),
'nickname': fighter.xpath('//td[3]/a//text()').extract_first(),
'height': fighter.xpath('//td[4]//text()').extract_first().strip(),
'weight': fighter.xpath('//td[5]//text()').extract_first().strip(),
'reach': fighter.xpath('//td[6]//text()').extract_first().strip(),
'stance': fighter.xpath('//td[7]//text()').extract_first().strip(),
'wins': fighter.xpath('//td[8]//text()').extract_first().strip(),
'losses': fighter.xpath('//td[9]//text()').extract_first().strip(),
'draws': fighter.xpath('//td[10]//text()').extract_first().strip(),
}
如果我取出 _first
,它会提取所有数据,但将其放在同一个单元格中并以相同的方式重复。
first last nickname height weight reach stance wins losses
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
Tom Aaron The Assassin -- 155 lbs. -- 5 3
....
您必须使用 relative xpath
仅在 fighter
内搜索 - 它必须以 dot
fighter.xpath('.//td[1]/a//text()')
没有 dot
它是 absolute xpath
并且它搜索所有 HTML 并且总是找到第一行。
但是你会遇到其他问题。
你得到了 table 中的所有行 - 甚至 header 没有 td
- 你必须跳过它。您可以使用 [1:]
for fighter in response.xpath(...)[1:]:
最少的工作代码。
您可以将所有内容复制到文件并作为普通脚本启动它 python script.py
而无需在 scrapy
import scrapy
class FightersSpider(scrapy.Spider):
name = "fighters"
start_urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
def start_requests(self):
urls = [
'http://www.ufcstats.com/statistics/fighters?char=a&page=all'
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response, **kwargs):
for fighter in response.xpath('//*[@class="b-statistics__table"]//tbody/tr')[1:]:
print(fighter.xpath('.//td[4]'))
yield {
'first': fighter.xpath('.//td[1]/a//text()').extract_first(),
'last': fighter.xpath('.//td[2]/a//text()').extract_first(),
'nickname': fighter.xpath('.//td[3]/a//text()').extract_first(),
'height': fighter.xpath('.//td[4]//text()').extract_first().strip(),
'weight': fighter.xpath('.//td[5]//text()').extract_first().strip(),
'reach': fighter.xpath('.//td[6]//text()').extract_first().strip(),
'stance': fighter.xpath('.//td[7]//text()').extract_first().strip(),
'wins': fighter.xpath('.//td[8]//text()').extract_first().strip(),
'losses': fighter.xpath('.//td[9]//text()').extract_first().strip(),
'draws': fighter.xpath('.//td[10]//text()').extract_first().strip(),
}
# --- 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
'FEEDS': {'output.csv': {'format': 'csv'}}, # new in 2.1
})
c.crawl(FightersSpider)
c.start()