Scrapy + Python,从网站查找链接时出错

时间:2018-09-18 08:29:34

标签: python json scrapy web-crawler

我正在尝试查找此页面所有事件的URL:

https://www.eventshigh.com/delhi/food?src=exp

但是我只能看到JSON格式的URL:

 {
    "@context":"http://schema.org",
    "@type":"Event",
    "name":"DANDIYA NIGHT 2018",
    "image":"https://storage.googleapis.com/ehimages/2018/9/4/img_b719545523ac467c4ad206c3a6e76b65_1536053337882_resized_1000.jpg",
    "url":"https://www.eventshigh.com/detail/Delhi/5b30d4b8462a552a5ce4a5ebcbefcf47-dandiya-night-2018",
    "eventStatus": "EventScheduled",

    "startDate":"2018-10-14T18:30:00+05:30",
    "doorTime":"2018-10-14T18:30:00+05:30",

      "endDate":"2018-10-14T22:30:00+05:30",

    "description" : "Dress code : TRADITIONAL (mandatory)\u00A0 \r\n Dandiya sticks will be available at the venue ( paid)\u00A0 \r\n Lip smacking food, professional dandiya Dj , media coverage , lucky draw \u00A0, Dandiya Garba Raas , Shopping and Games .\u00A0 \r\n \u00A0 \r\n Winners\u00A0 \r\n \u00A0 \r\n Best dress ( all",
    "location":{
      "@type":"Place",


          "name":"K And L Community Hall (senior Citizen Complex )",


          "address":"80 TO 49, Pocket K, Sarita Vihar, New Delhi, Delhi 110076, India"



    },

这里是:

"url":"https://www.eventshigh.com/detail/Delhi/5b30d4b8462a552a5ce4a5ebcbefcf47-dandiya-night-2018"

但是我找不到包含链接的任何其他HTML / XML标签。我也找不到包含链接的相应JSON文件。您能帮我抓取此页面所有事件的链接吗?

https://www.eventshigh.com/delhi/food?src=exp

1 个答案:

答案 0 :(得分:0)

从这样一个基于JavaScript的页面收集信息,乍一看可能令人生畏;但是实际上,由于所有信息都集中在一个地方,而不是分散在许多昂贵的HTTP请求查询中,因此通常可以提高生产力。

因此,当页面向您提供这样的JSON数据时,您可以通过对服务器友好并使用它来感谢他们! :)
您已经花了一些时间来进行“源视图分析”,这比尝试通过(昂贵的)Selenium / Splash / ect.-renderpipe获取信息要有效。

实现该目标的宝贵工具是 XPath 。有时可能需要我们的朋友regex的一点额外帮助。
假设您已成功获取页面,并拥有一个Scrapy response对象(或者您在另外收集的响应正文上有一个Parsel.Selector()),则可以访问xpath()方法为response.xpathselector.xpath

>>> response.status
200

您已经确定数据以纯文本(json)的形式存在,因此我们需要向下钻取至其隐藏位置,以最终提取原始JSON内容。 之后,将其转换为Python字典以进一步使用将是微不足道的。 在这种情况下,它位于容器节点<script type="application/ld+json">中。我们的XPath可能如下所示:

>>> response.xpath('//script[@type="application/ld+json"]')
[<Selector xpath='//script[@type="application/ld+json"]' data='<script type="application/ld+json">\n{\n  '>,
 <Selector xpath='//script[@type="application/ld+json"]' data='<script type="application/ld+json">\n{\n  '>,
 <Selector xpath='//script[@type="application/ld+json"]' data='<script type="application/ld+json">\n    '>]

这将在xml页面中找到每个“脚本” 节点,该节点的属性为“类型”,且 value 为“ application / ld” + json”。 显然,这还不够具体,因为我们发现了三个节点(Selector包装在返回的列表中)。

根据您的分析,我们知道JSON必须包含"@type":"Event",因此让我们的xpath为此进行一些子字符串搜索:

>>> response.xpath("""//script[@type="application/ld+json"]/self::node()[contains(text(), '"@type":"Event"')]""")
[<Selector xpath='//script[@type="application/ld+json"]/self::node()[contains(text(), \'"@type":"Event"\')]' data='<script type="application/ld+json">\n    '>]

在这里,我们添加了第二个限定符,该限定符表示我们的script 节点必须包含给定的 text
('self :: node()'显示了一些XPath轴魔术,可以在此时参考到我们当前的script节点-而不是其后代。不过,我们将对此进行简化。)
现在,我们的返回列表包含一个节点/选择器。从data=字符串中可以看出,如果要extract(),现在 得到诸如<script type="application/ld+json">[...]</script>之类的字符串。 由于我们关心的是节点的内容,而不是节点本身,因此,我们还有一步:

>>> response.xpath("""//script[@type="application/ld+json"][contains(text(), '"@type":"Event"')]/text()""")
[<Selector xpath='//script[@type="application/ld+json"][contains(text(), \'"@type":"Event"\')]/text()' data='\n        [\n          \n            \n     '>]

这将返回目标SelectorList中的text()。如您所见,我们也可以取消自我参照。 现在,xpath()总是返回一个SelectorList,但是我们为此提供了一些帮助:response.xpath().extract_first()将在处理列表之前获取列表的第一个元素-检查它是否存在。 我们可以将结果放入data变量中,然后将json.loads(data)放入Python字典中并查看我们的值很简单:

>>> events = json.loads(data)
>>> [item['url'] for item in events]
['<url>',
 '<url>',
 '<url>',
 '<url>']

现在,您可以将它们变成scrapy.Request(url)了,您将知道如何从那里继续。


一如既往,负责任地进行爬网,并保持'net是一个不错的地方。我不认可任何非法行为。
评估自己的权利或获得访问指定目标资源的许可是自己的责任。