使用 scrapy、规则和 link 提取器抓取 "older" 页面
Scraping "older" pages with scrapy, rules and link extractors
我一直在用 scrapy 做一个项目。在这个可爱的社区的帮助下,我设法抓取了该网站的第一页:http://www.rotoworld.com/playernews/nfl/football-player-news?ls=roto%3anfl%3agnav。我也在尝试从 "older" 页面中抓取信息。我研究了 "crawlspider"、规则和 link 提取器,并相信我有正确的代码。我希望蜘蛛在后续页面上执行相同的循环。不幸的是,在我 运行 它的那一刻,它只吐出第一页,并没有继续到 "older" 页。
我不太确定我需要更改什么,非常感谢您的帮助。有 post 一直追溯到 2004 年 2 月...我是数据挖掘的新手,不确定能够抓取每个 post 是否真的是一个现实的目标。如果是的话,我愿意。请任何帮助表示赞赏。谢谢!
import scrapy
from scrapy.contrib.spiders import CrawlSpider,Rule
from scrapy.contrib.linkextractors import LinkExtractor
class Roto_News_Spider2(crawlspider):
name = "RotoPlayerNews"
start_urls = [
'http://www.rotoworld.com/playernews/nfl/football/',
]
Rules = (Rule(LinkExtractor(allow=(), restrict_xpaths=('//input[@id="cp1_ctl00_btnNavigate1"]',)), callback="parse_page", follow= True),)
def parse(self, response):
for item in response.xpath("//div[@class='pb']"):
player = item.xpath(".//div[@class='player']/a/text()").extract_first()
position= item.xpath(".//div[@class='player']/text()").extract()[0].replace("-","").strip()
team = item.xpath(".//div[@class='player']/a/text()").extract()[1].strip()
report = item.xpath(".//div[@class='report']/p/text()").extract_first()
date = item.xpath(".//div[@class='date']/text()").extract_first() + " 2018"
impact = item.xpath(".//div[@class='impact']/text()").extract_first().strip()
source = item.xpath(".//div[@class='source']/a/text()").extract_first()
yield {"Player": player,"Position": position, "Team": team,"Report":report,"Impact":impact,"Date":date,"Source":source}
我的建议:硒
如果你想自动换页,你可以使用Selenium WebDriver。
Selenium
使您能够与页面进行交互,点击按钮,输入输入等。您需要更改代码以废弃 data
,然后点击 older
按钮。然后,它会改变页面并继续抓取。
Selenium
是一个非常有用的工具。我现在正在个人项目中使用它。你可以看看 my repo on GitHub 看看它是如何工作的。对于您要废弃的页面,您不能仅仅将 link
更改为 scraped
就转到旧页面,因此,您需要使用 Selenium
在两者之间进行更改页数。
希望对您有所帮助。
在当前情况下无需使用 Selenium。在抓取之前,您需要在浏览器中打开 url 并按 F12 检查代码并在“网络”选项卡中查看数据包。当您按下一步或 "OLDER" 在您的情况下,您可以在网络选项卡中看到一组新的 TCP 数据包。它为您提供所需的一切。当您了解它的工作原理后,您就可以编写工作蜘蛛了。
import scrapy
from scrapy import FormRequest
from scrapy.contrib.spiders import CrawlSpider,Rule
from scrapy.contrib.linkextractors import LinkExtractor
class Roto_News_Spider2(CrawlSpider):
name = "RotoPlayerNews"
start_urls = [
'http://www.<DOMAIN>/playernews/nfl/football/',
]
Rules = (Rule(LinkExtractor(allow=(), restrict_xpaths=('//input[@id="cp1_ctl00_btnNavigate1"]',)), callback="parse", follow= True),)
def parse(self, response):
for item in response.xpath("//div[@class='pb']"):
player = item.xpath(".//div[@class='player']/a/text()").extract_first()
position= item.xpath(".//div[@class='player']/text()").extract()[0].replace("-","").strip()
team = item.xpath(".//div[@class='player']/a/text()").extract()[1].strip()
report = item.xpath(".//div[@class='report']/p/text()").extract_first()
date = item.xpath(".//div[@class='date']/text()").extract_first() + " 2018"
impact = item.xpath(".//div[@class='impact']/text()").extract_first().strip()
source = item.xpath(".//div[@class='source']/a/text()").extract_first()
yield {"Player": player,"Position": position, "Team": team,"Report":report,"Impact":impact,"Date":date,"Source":source}
older = response.css('input#cp1_ctl00_btnNavigate1')
if not older:
return
inputs = response.css('div.aspNetHidden input')
inputs.extend(response.css('div.RW_pn input'))
formdata = {}
for input in inputs:
name = input.css('::attr(name)').extract_first()
value = input.css('::attr(value)').extract_first()
formdata[name] = value or ''
formdata['ctl00$cp1$ctl00$btnNavigate1.x'] = '42'
formdata['ctl00$cp1$ctl00$btnNavigate1.y'] = '17'
del formdata['ctl00$cp1$ctl00$btnFilterResults']
del formdata['ctl00$cp1$ctl00$btnNavigate1']
action_url = 'http://www.<DOMAIN>/playernews/nfl/football-player-news?ls=roto%3anfl%3agnav&rw=1'
yield FormRequest(
action_url,
formdata=formdata,
callback=self.parse
)
请注意,您需要将我的代码中的所有内容都替换为正确的代码。
如果您的目的是获取遍历多个页面的数据,则无需使用 scrapy。如果你还想有任何与 scrapy 相关的解决方案,那么我建议你选择 splash 来处理分页。
我会做类似下面的事情来获取项目(假设你已经在你的机器上安装了 selenium):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("http://www.rotoworld.com/playernews/nfl/football/")
wait = WebDriverWait(driver, 10)
while True:
for item in wait.until(EC.presence_of_all_elements_located((By.XPATH,"//div[@class='pb']"))):
player = item.find_element_by_xpath(".//div[@class='player']/a").text
player = player.encode() #it should handle the encoding issue; I'm not totally sure, though
print(player)
try:
idate = wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='date']"))).text
if "Jun 9" in idate: #put here any date you wanna go back to (last limit: where the scraper will stop)
break
wait.until(EC.presence_of_element_located((By.XPATH, "//input[@id='cp1_ctl00_btnNavigate1']"))).click()
wait.until(EC.staleness_of(item))
except:break
driver.quit()
我一直在用 scrapy 做一个项目。在这个可爱的社区的帮助下,我设法抓取了该网站的第一页:http://www.rotoworld.com/playernews/nfl/football-player-news?ls=roto%3anfl%3agnav。我也在尝试从 "older" 页面中抓取信息。我研究了 "crawlspider"、规则和 link 提取器,并相信我有正确的代码。我希望蜘蛛在后续页面上执行相同的循环。不幸的是,在我 运行 它的那一刻,它只吐出第一页,并没有继续到 "older" 页。
我不太确定我需要更改什么,非常感谢您的帮助。有 post 一直追溯到 2004 年 2 月...我是数据挖掘的新手,不确定能够抓取每个 post 是否真的是一个现实的目标。如果是的话,我愿意。请任何帮助表示赞赏。谢谢!
import scrapy
from scrapy.contrib.spiders import CrawlSpider,Rule
from scrapy.contrib.linkextractors import LinkExtractor
class Roto_News_Spider2(crawlspider):
name = "RotoPlayerNews"
start_urls = [
'http://www.rotoworld.com/playernews/nfl/football/',
]
Rules = (Rule(LinkExtractor(allow=(), restrict_xpaths=('//input[@id="cp1_ctl00_btnNavigate1"]',)), callback="parse_page", follow= True),)
def parse(self, response):
for item in response.xpath("//div[@class='pb']"):
player = item.xpath(".//div[@class='player']/a/text()").extract_first()
position= item.xpath(".//div[@class='player']/text()").extract()[0].replace("-","").strip()
team = item.xpath(".//div[@class='player']/a/text()").extract()[1].strip()
report = item.xpath(".//div[@class='report']/p/text()").extract_first()
date = item.xpath(".//div[@class='date']/text()").extract_first() + " 2018"
impact = item.xpath(".//div[@class='impact']/text()").extract_first().strip()
source = item.xpath(".//div[@class='source']/a/text()").extract_first()
yield {"Player": player,"Position": position, "Team": team,"Report":report,"Impact":impact,"Date":date,"Source":source}
我的建议:硒
如果你想自动换页,你可以使用Selenium WebDriver。
Selenium
使您能够与页面进行交互,点击按钮,输入输入等。您需要更改代码以废弃 data
,然后点击 older
按钮。然后,它会改变页面并继续抓取。
Selenium
是一个非常有用的工具。我现在正在个人项目中使用它。你可以看看 my repo on GitHub 看看它是如何工作的。对于您要废弃的页面,您不能仅仅将 link
更改为 scraped
就转到旧页面,因此,您需要使用 Selenium
在两者之间进行更改页数。
希望对您有所帮助。
在当前情况下无需使用 Selenium。在抓取之前,您需要在浏览器中打开 url 并按 F12 检查代码并在“网络”选项卡中查看数据包。当您按下一步或 "OLDER" 在您的情况下,您可以在网络选项卡中看到一组新的 TCP 数据包。它为您提供所需的一切。当您了解它的工作原理后,您就可以编写工作蜘蛛了。
import scrapy
from scrapy import FormRequest
from scrapy.contrib.spiders import CrawlSpider,Rule
from scrapy.contrib.linkextractors import LinkExtractor
class Roto_News_Spider2(CrawlSpider):
name = "RotoPlayerNews"
start_urls = [
'http://www.<DOMAIN>/playernews/nfl/football/',
]
Rules = (Rule(LinkExtractor(allow=(), restrict_xpaths=('//input[@id="cp1_ctl00_btnNavigate1"]',)), callback="parse", follow= True),)
def parse(self, response):
for item in response.xpath("//div[@class='pb']"):
player = item.xpath(".//div[@class='player']/a/text()").extract_first()
position= item.xpath(".//div[@class='player']/text()").extract()[0].replace("-","").strip()
team = item.xpath(".//div[@class='player']/a/text()").extract()[1].strip()
report = item.xpath(".//div[@class='report']/p/text()").extract_first()
date = item.xpath(".//div[@class='date']/text()").extract_first() + " 2018"
impact = item.xpath(".//div[@class='impact']/text()").extract_first().strip()
source = item.xpath(".//div[@class='source']/a/text()").extract_first()
yield {"Player": player,"Position": position, "Team": team,"Report":report,"Impact":impact,"Date":date,"Source":source}
older = response.css('input#cp1_ctl00_btnNavigate1')
if not older:
return
inputs = response.css('div.aspNetHidden input')
inputs.extend(response.css('div.RW_pn input'))
formdata = {}
for input in inputs:
name = input.css('::attr(name)').extract_first()
value = input.css('::attr(value)').extract_first()
formdata[name] = value or ''
formdata['ctl00$cp1$ctl00$btnNavigate1.x'] = '42'
formdata['ctl00$cp1$ctl00$btnNavigate1.y'] = '17'
del formdata['ctl00$cp1$ctl00$btnFilterResults']
del formdata['ctl00$cp1$ctl00$btnNavigate1']
action_url = 'http://www.<DOMAIN>/playernews/nfl/football-player-news?ls=roto%3anfl%3agnav&rw=1'
yield FormRequest(
action_url,
formdata=formdata,
callback=self.parse
)
请注意,您需要将我的代码中的所有内容都替换为正确的代码。
如果您的目的是获取遍历多个页面的数据,则无需使用 scrapy。如果你还想有任何与 scrapy 相关的解决方案,那么我建议你选择 splash 来处理分页。
我会做类似下面的事情来获取项目(假设你已经在你的机器上安装了 selenium):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("http://www.rotoworld.com/playernews/nfl/football/")
wait = WebDriverWait(driver, 10)
while True:
for item in wait.until(EC.presence_of_all_elements_located((By.XPATH,"//div[@class='pb']"))):
player = item.find_element_by_xpath(".//div[@class='player']/a").text
player = player.encode() #it should handle the encoding issue; I'm not totally sure, though
print(player)
try:
idate = wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='date']"))).text
if "Jun 9" in idate: #put here any date you wanna go back to (last limit: where the scraper will stop)
break
wait.until(EC.presence_of_element_located((By.XPATH, "//input[@id='cp1_ctl00_btnNavigate1']"))).click()
wait.until(EC.staleness_of(item))
except:break
driver.quit()