使用Scrapy抓取使用XMLHttpRequests加载其内容的网站

时间:2019-04-17 19:23:27

标签: python json ajax scrapy

我尝试抓取的网站(在浏览器中)一次返回50个职位。当我尝试使用scrapy返回所有职位时,只会刮掉20个职位。

链接到网页: https://recruiting.ultipro.com/COM1038/JobBoard/d22da326-8928-4fbc-8b3b-99b6db355d5d/?q=&o=postedDateDesc

进入该页面后,我意识到内容是动态呈现的,因此我右键单击并检查了该页面,并使用在Dev Tools中打开的XHR>网络选项卡将其重新加载。它显示了两个文件

  1. GetFilters
  2. LoadOpportunities

“ LoadOpportunities”似乎很有希望,因此我查看了XHR选项卡下的“ Response”,它返回的似乎是一个JSON文件,其中包含我可能想要的所有信息。我使用CTRL-f搜索“标题”,并发现了50个事件。完美!

然后进行测试。我打开了Scrapy Shell,并查看了返回JSON的页面:

https://recruiting.ultipro.com/COM1038/JobBoard/d22da326-8928-4fbc-8b3b-99b6db355d5d/JobBoardView/LoadOpportunities

在浏览器中打开此页面时,它仅返回(当前)54个职位空缺中的20个。当我使用json包和scrapy shell刮页面时,我首先发现了这一点。

当您使用我在“ LoadOpportunities”文件下发布的第一个链接查看浏览器中的“ Preview”选项卡时,您会发现它在“ opportunities”键下最多包含50个值。从每个值中抓取“标题”值。

我还创建了一个刮板,它使用HTML响应执行相同的操作,但是它并不是特别有用。由于它实际上并未与动态网页进行交互,而只是与初始页面连接的部分JSON文件进行交互,因此无法完成工作。

import scrapy, re, json, requests
from ..items import MetroSouthItems

class MetroSouth(scrapy.Spider):
    name = "metrosouth"
    start_urls = [
    'https://recruiting.ultipro.com/COM1038/JobBoard/d22da326-8928-4fbc-8b3b-99b6db355d5d/JobBoardView/LoadOpportunities',
    ]

    def parse(self, response):
        html_res = response.body
        decoded_res = str(html_res,"utf-8")
        json_file = open("metrosouth.json", "w")
        json_file.write(decoded_res)
        with open("metrosouth.json") as json_data:
            data = json.load(json_data)
            items = MetroSouthItems()
            for i in range(len(data["opportunities"])):
                items["job_title"] = data["opportunities"][i]["Title"]
                print(i)
                yield items

我想把所有可用的工作都刮掉,然后在某个时候将这些工作铲到数据库中/可能每天早上重新运行蜘蛛程序,以便跟踪新列表。现在,我用新清单覆盖了JSON文件。

如果任何人有前进的任何提示或指导,我将不胜感激。我感觉它与Javascript有关,因为它确实说“ LoadOpportunities”是由jslib发起的,但是我对JavaScript没有太多的经验,也不知道这意味着什么。

1 个答案:

答案 0 :(得分:2)

最初,他们在页面中发出带有一些额外有效负载的POST请求。我们可以使用以下方式重现它:

override func viewWillAppear(_ animated: Bool) {

        fetchAllBeerOrders { beerOrders in
            self.orders = beerOrders!
            //print("Beer fetch: ", self.orders)
            self.tableView.reloadData()
        }

        fetchAllCocktailOrders { coctailOrders in
          self.orders.append(coctailOrders)
            //print("Cocktail fetch: ", self.orders)
            self.tableView.reloadData()
        }

    }

检查有效负载中的参数import scrapy, json class MetroSouth(scrapy.Spider): name = "metrosouth" search_url = url = 'https://recruiting.ultipro.com/COM1038/JobBoard/d22da326-8928-4fbc-8b3b-99b6db355d5d/JobBoardView/LoadOpportunities' def start_requests(self): payload = """{"opportunitySearch":{"Top":100,"Skip":0,"QueryString":"","OrderBy":[{"Value":"postedDateDesc","PropertyName":"PostedDate","Ascending":false}],"Filters":[{"t":"TermsSearchFilterDto","fieldName":4,"extra":null,"values":[]},{"t":"TermsSearchFilterDto","fieldName":5,"extra":null,"values":[]},{"t":"TermsSearchFilterDto","fieldName":6,"extra":null,"values":[]}]},"matchCriteria":{"PreferredJobs":[],"Educations":[],"LicenseAndCertifications":[],"Skills":[],"hasNoLicenses":false,"SkippedSkills":[]}}""" yield scrapy.Request(self.search_url, method='POST', body=payload) def parse(self, response): j = json.loads(response.text) print '======' for i, row in enumerate(j.get('opportunities')): print i, ' - ', row.get('Title') print '======' 。最初将其设置为50,并且请求翻页会给我们20条记录。但是我将其增加到100,现在我获得了所有54条记录。 希望对您有所帮助。