urllib2和BeautifulSoup没有拉完整个网页

时间:2016-06-09 15:19:01

标签: python beautifulsoup urllib2

我和朋友正试图在我们频繁出现的棒球博客上计算一些评论指标(有多少用户评论某些帖子,评论谁,每个用户添加了多少条评论等)。

我对网页编程或抓取知之甚少,但我知道一些Python,所以我自愿提供帮助(她正在复制并将评论粘贴到.txt文件中并使用 Cmd + F来记录评论)。

我的初始方法使用了urllib2和BeautifulSoup(Python 2.7):

import sys,re,csv,glob,os
from collections import Counter
import urllib2
from bs4 import BeautifulSoup

url = "http://www.royalsreview.com/2016/6/8/11881484/an-analysis-of-rr-game-threads#comments"
f = urllib2.urlopen(url).read()
soup = BeautifulSoup(f)

userlist = soup.find_all("div", class_="comment")

通过在Chrome浏览器中访问该网址并点击" Inspect"我有点了解我要查找的内容。在评论中,它向我展示了我需要记录评论的HTML位。

但是,当我使用urllib2读取URL时,它提取的HTML不包含该网页上的注释。

从我的研究中,我认为这是因为urllib2将从服务器获取页面的来源,但它不会包含JavaScript生成的内容(我冒险来自我舒适的地方,这里)或其他什么(例如评论)。

如何通过添加评论来获取用户更改后的页面?

感谢您的帮助

3 个答案:

答案 0 :(得分:1)

您可以通过向http://www.royalsreview.com/comments/load_comments/11645525发送获取请求,以 json 格式获取数据:

import requests
from collections import Counter
from operator import itemgetter
url = "http://www.royalsreview.com/comments/load_comments/11645525"
js =  requests.get(url).json()
cn = Counter(map(itemgetter("username"), js["comments"]))

print(cn)

这给了你:

Counter({u'artzfreak': 20, u'RoyallyDisplaced': 9, u'sterlingice': 8, u'Max Rieper': 6, u'Scott McKinney': 6, u'Cody.McElroy': 3, u'GrassyKnoll': 3, u'Farmhand': 3, u'Minda Haas Kuhlmann': 3, u'Warden11': 2, u'nom nom nom de plume': 2, u'1040X': 2, u'Nighthawk at the Diner': 2, u'thelaundry': 2, u'Gopherballs': 2, u"Daenerys C. O'sFanaryen": 1, u'Shaun Newkirk': 1, u'Blue and Red': 1, u'wcgrad': 1, u'MrAndersonmm': 1, u'DCChiefFan': 1, u'J.K. Ward': 1, u'philofthenorth': 1, u'Mink Farmer': 1, u'keith jersey': 1, u'Kevin Ruprecht': 1, u'Tim Webber': 1, u'Matthew LaMar': 1, u'MightyMinx': 1, u'Quisenberry4Ever': 1, u'Daloath': 1, u'HalsHatsCrooked': 1, u'pete_clarf': 1})

如果您打印js["comments"],您会看到一系列代码:

{u'ancestry': u'0379481445',
  u'bad_flags_count': 0,
  u'body': u'<blockquote>So maybe it\u2019s as hunter s. royal suggested, and it\u2019s because philofthenorth got a job.</blockquote>',
  u'created_on': u'2016-06-08T17:35:09.000Z',
  u'created_on_long': u'Jun  8, 2016 |  1:35 PM',
  u'created_on_short': u'06.08.16  1:35pm',
  u'created_on_timestamp': 1465407309,
  u'depth': 1,
  u'entry_id': 11645525,
  u'hidden': False,
  u'id': 379481445,
  u'inappropriate_flags_count': 0,
  u'parent_id': None,
  u'permalink': u'/2016/6/8/11881484/an-analysis-of-rr-game-threads/comment/379481445',
  u'recommended_flags_count': 5,
  u'shortlink': u'/c/379481445',
  u'signature': u'',
  u'spam_flags_count': 0,
  u'title': u'Love it',
  u'troll_flags_count': 0,
  u'user_id': 153964,
  u'username': u'sterlingice',
  u'version': 1}

每条评论都有自己的词典,并保留上述所有信息。

要不必硬编码 entry_id ,e可以从实际页面解析它,然后将其传递到:

import requests
from collections import Counter
from operator import itemgetter

init_url = "http://www.royalsreview.com/2016/6/8/11881484/an-analysis-of-rr-game-threads#comments"

url = "http://www.royalsreview.com/comments/load_comments/{}"
entry_id = BeautifulSoup(requests.get(init_url).content).select_one("h2.m-entry__title")["data-remote-admin-entry-id"]
print(entry_id)
js = requests.get(url.format(entry_id)).json()
cn = Counter(map(itemgetter("username"), js["comments"]))

print(cn)

所以不需要任何javascript,你可以在格式良好的json中获得所有数据。

答案 1 :(得分:0)

使用Selenium或Dryscape。 Selenium打开了一个Web浏览器,你实际上可以看到它做的事情。由于使用了浏览器,它也会呈现Javascript。

我注意到页面来源中显示的评论数量。

<span class="comments-count">80</span>

您可以抓取此范围以获取评论数量。你可以在不同的时间点抓住这个范围,看是否有新评论(人们不太可能删除评论)

以下是使用Selenium抓取它的代码。

from selenium import webdriver
driver = webdriver.Firefox() # Opens firefox
driver.get('http://www.royalsreview.com/2016/6/8/11881484/an-analysis-of-rr-game-threads#comments')
userlist = driver.find_elements_by_class_name('comment') 
# ^ Finds all elements with the class comment and stores it in a list

# userlist is a list of all the tags with the class comment

print userlist[0].text 

上面的print语句给出了(页面中的第一条评论)。

喜欢它 也许这就像猎人一样。皇室建议,这是因为philofthenorth得到了一份工作。 来自Sterlingice于2016年6月8日|下午1:35回复

使用userlist [1] .text打印第二条评论,依此类推。

我建议你使用

print len(userlist) 

与页面上的评论数量交叉引用。该页面显示有80条评论,但用户列表的长度为82.请务必交叉检查。

如果您有任何疑问,请告诉我们:)

答案 2 :(得分:0)

我最终做了什么:

import sys,re,csv,glob,os
from collections import Counter
import dryscrape
from bs4 import BeautifulSoup

url = "http://www.royalsreview.com/2016/6/8/11881484/an-analysis-of-rr-game-threads#comments"

session = dryscrape.Session()
session.visit(url)
f = session.body()
soup = BeautifulSoup(f)

posterSoup = soup.find_all("a", class_="poster")
posterList = []
for poster in posterSoup:
    posterList.append(poster.string.lstrip())

posterCount = Counter(posterList)
with open('metrics.txt', 'w') as out:
    for entry in posterCount:
        out.write(entry + "\t" + str(posterCount[entry]) + "\n")

我真正想要的是每张海报提交的评论数量。因此,我删除了所有注释,将它们放入列表中,并使用Counter将该列表折叠到计数器容器中。然后,我可以打印出海报的用户名,然后打印该用户提供的评论数量。