使用Scrapy(Python)进行Web数据抓取(在线新闻评论)

时间:2013-11-26 13:49:21

标签: python web-scraping scrapy

我想从在线新闻中搜索网络评论数据纯粹是为了研究。而且我注意到我必须学习Scrapy ......

通常,我使用Python进行编程。我虽然很容易学习。但是我遇到了一些问题。

我想在http://news.yahoo.com/congress-wary--but-unlikely-to-blow-up-obama-s-iran-deal-230545228.html抓取新闻评论。

但问题是有一个按钮(>查看评论(452))来查看评论。另外,我想要做的是抓取该新闻中的所有评论。不幸的是,我必须单击另一个按钮(查看更多评论)以查看其他10条评论。

我该如何处理这个问题?

我所做的代码如下。对不起代码太差了。

#############################################
from scrapy.spider import BaseSpider
from scrapy.selector import Selector
from tutorial.items import DmozItem

class DmozSpider(BaseSpider):
   name = "dmoz"
   allowed_domains = ["news.yahoo.com"]

   start_urls = ["http://news.yahoo.com/blogs/oddnews/driver-offended-by-%E2%80%9Cwh0-r8x%E2`%80%9D-license-plate-221720503.html",]

   def parse(self, response):
       sel = Selector(response)
       sites = sel.xpath('//div/p')
       items = []
       for site in sites:
           item = DmozItem()
           item['title'] = site.xpath('/text()').extract()
           items.append(item)
       return items  

你可以看到要解决我的问题需要做多少工作。但我必须要快点..无论如何我会尽力而为。

2 个答案:

答案 0 :(得分:3)

既然你看起来像先试问问题(这是一件非常好的事情),我不会给你一个答案,而是一个关于如何找到答案的(非常详细的)指南。

问题是,除非您是雅虎开发人员,否则您可能无法访问您尝试抓取的源代码。也就是说,您不确切地知道网站是如何构建的,以及您在服务器端如何处理对用户的请求。但是,您可以调查客户端并尝试模拟它。我喜欢使用Chrome开发者工具,但你可以使用其他如FF firebug。

首先,我们需要弄清楚发生了什么。所以它的工作方式是,你点击“显示评论”它加载前十个,然后你需要每次点击接下来的十条评论。但请注意,所有这些点击都不会将您带到另一个链接,但是生动地提取注释,这是一个非常简洁的UI,但对于我们的情况需要更多的工作。我可以马上讲两件事:

  1. 他们正在使用javascript加载评论(因为我停留在同一页面上)。
  2. 每次单击时都会使用AJAX调用动态加载它们(意味着不是在页面上加载注释而只是向您展示它们,每次单击它都会向数据库发出另一个请求)。
  3. 现在让我们右键单击并检查该按钮上的元素。它实际上只是一个简单的文本范围:

    <span>View Comments (2077)</span>
    

    通过观察我们仍然不知道如何生成或点击时它做了什么。精细。现在,保持devtools窗口打开,让我们点击它。这开辟了前十名。但实际上,我们正在请求获取它们。 chrome devtools录制的请求。我们查看devtools的网络选项卡,看到很多令人困惑的数据。等等,这是有道理的:

    http://news.yahoo.com/_xhr/contentcomments/get_comments/?content_id=42f7f6e0-7bae-33d3-aa1d-3dfc7fb5cdfc&_device=full&count=10&sortBy=highestRated&isNext=true&offset=20&pageNumber=2&_media.modules.content_comments.switches._enable_view_others=1&_media.modules.content_comments.switches._enable_mutecommenter=1&enable_collapsed_comment=1
    

    请参阅? _xhr然后get_comments。这很有道理。在浏览器中转到该链接给了我一个JSON对象(看起来像一个python字典),其中包含该请求获取的所有十条注释。现在这是你需要模仿的请求,因为那是给你你想要的东西。首先让我们将其翻译成人类可以阅读的正常要求:

    go to this url: http://news.yahoo.com/_xhr/contentcomments/get_comments/
    include these parameters: {'_device': 'full',
              '_media.modules.content_comments.switches._enable_mutecommenter': '1',
              '_media.modules.content_comments.switches._enable_view_others': '1',
              'content_id': '42f7f6e0-7bae-33d3-aa1d-3dfc7fb5cdfc',
              'count': '10',
              'enable_collapsed_comment': '1',
              'isNext': 'true',
              'offset': '20',
              'pageNumber': '2',
              'sortBy': 'highestRated'}
    

    现在只是一个试错的问题。但是,请注意以下几点:

    1. 显然,计算是决定你收到多少评论的原因。我尝试将其更改为100以查看发生了什么并得到了错误的请求。它足以告诉我为什么 - “偏移量应该是总行数的倍数”。所以现在我们了解如何使用offset

    2. content_id可能是标识您正在阅读的文章的内容。意思是你需要以某种方式从原始页面获取它。尝试挖掘一下,你会发现它。

    3. 另外,你显然不想一次获取10条评论,所以找到一种方法来获取总评论的数量可能是一个好主意(要么找出页面如何得到它,或者只是从文章本身中获取它)

    4. 使用devtools可以访问所有客户端脚本。因此,通过挖掘,您可以发现/ get_comments /的链接保存在名为YUI的javascript对象中。然后,您可以尝试了解它是如何发出请求的,并尝试模拟它(尽管您可能自己想出来)

    5. 您可能需要克服一些安全措施。例如,在访问注释之前,您可能需要原始文章中的会话密钥。这用于防止直接访问站点的某些部分。我不会麻烦你的细节,因为在这种情况下它似乎不是一个问题,但你需要知道它,以防它出现。

    6. 最后,你必须解析JSON对象(python有很好的内置工具),然后解析你得到的html注释(你可能想要查看{{3} })。

    7. 正如你所看到的,这将需要一些工作,但尽管我已经写过,但这也不是一项非常复杂的任务。

      所以不要惊慌。

      这只是挖掘和挖掘的问题,直到你找到黄金(同样,有一些基本的WEB知识不会受到伤害)。然后,如果你遇到障碍而真的无法继续前进,请回到这里,再问一遍。有人会帮助你。

      祝你好运!

答案 1 :(得分:0)

我很感谢这个问题,因为它让我开始试图抓取雅虎评论,我只是想添加一个更新,因为雅虎已经改变了他们处理评论的方式,因为这个问题已经发布。首先,有3个感兴趣的URL,具体取决于您想要获得的内容。通过这些,您可以获得主要评论主题,对主题的回复或来自用户的评论。这些是

urlComments = 'https://www.yahoo.com/news/_td/api/resource/canvass.getMessageListForContext_ns;context=%1s;count=10;index=%1s;lang=en-US;namespace=yahoo_content;oauthConsumerKey=frontpage.oauth.canvassKey;oauthConsumerSecret=frontpage.oauth.canvassSecret;rankingProfile=canvassHalfLifeDecayProfile;region=US;sortBy=popular;type=null;userActivity=true'
urlReply = 'https://www.yahoo.com/news/_td/api/resource/canvass.getReplies_ns;context=%1s;count=10;index=%1s;lang=en-US;messageId=%1s;namespace=yahoo_content;oauthConsumerKey=frontpage.oauth.canvassKey;oauthConsumerSecret=frontpage.oauth.canvassSecret;region=US;sortBy=createdAt;tags='
urlUser = 'https://www.yahoo.com/news/_td/api/resource/canvass.getUserMessageHistory;count=10;index=%1s;lang=en-US;oauthConsumerKey=frontpage.oauth.canvassKey;oauthConsumerSecret=frontpage.oauth.canvassSecret;region=US;sortBy=createdAt;userId=%1s'

现在,我已经在URL中插入了几个%1s,以便将所需的变量插入到URL中,例如文章ID,索引或用户ID。和以前一样,需要一些参数:

params = {'bkt': ["news-d-202","newsdmcntr"],
    'device': 'desktop',
    'feature': 'cacheContentCanvas,videoDocking,newContentAttribution,livecoverage,featurebar,deferModalCluster,specRetry,newLayout,sidepic,canvassOffnet,ntkFilmstrip,autoNotif,CanvassTags',
    'intl': 'us',
    'lang': 'en-US',
    'partner': 'none',
    'prid': '5t11qvhclanab',
    'region': 'US',
    'site': 'fp',
    'tz': 'America/PICKACITY',  <-- insert a city
    'ver': '2.0.7765',
    'returnMeta': 'true'}

使用requests库,我们可以提出评论,比如说。

response = requests.get(u, params=params) #u is a url from above
coms = response.json()['data']['canvassMessages'] #drop the ['canvassMessages'] if you want to get replies to a thread

从那里,您可以从评论中提取您想要的任何内容。现在,coms只会有10条评论(如果您查看网址,您会看到count=10 - 不幸的是,最大值似乎是30)。要获得下一组10,请将coms[-1]['index']值插入所需的URL,然后抓住下一个10.但是,我遇到的问题是,在雅虎点击之前你只能获得大约1000条评论。例如,如果您访问this comment page,则会看到注释1000-1009(找到“索引”值,并获得类似v=1:s=popular:sl=1498836633:off=1000的内容)。但是如果你访问this next comment page,你应该看到评论1010-1019,但实际上没有加载评论。这很烦人,如果有人知道如何克服这个问题,我会非常欢迎这个解决方案。最后,为了获取文章ID,打开页面源,搜索"pstaid",然后复制其后面的值。例如,以上链接适用于This article with lots of comments的评论。如果您搜索"pstaid",则会找到值0efc85df-eb0b-373e-b6f3-4c513ed2a415,这是您要插入到网址中的文章ID。