【问题标题】:Urllib Python is not providing with the html code I see with with inspect elementUrllib Python 没有提供我在检查元素中看到的 html 代码
【发布时间】:2014-11-13 12:22:27
【问题描述】:

我正在尝试抓取此链接中的结果:

url = "http://topsy.com/trackback?url=http%3A%2F%2Fmashable.com%2F2014%2F08%2F27%2Faustralia-retail-evolution-lab-aopen-shopping%2F"

当我用 firebug 检查它时,我可以看到 html 代码,并且我知道我需要做什么来提取推文。问题是当我使用 urlopen 获得响应时,我没有得到相同的 html 代码。我只得到标签。我错过了什么?

示例代码如下:

   def get_tweets(section_url):
     html = urlopen(section_url).read()
     soup = BeautifulSoup(html, "lxml")
     tweets = soup.find("div", "results")
     category_links = [dd.a["href"] for tweet in tweets.findAll("div", "result-tweet")]
     return category_links

url =  "http://topsy.com/trackback?url=http%3A%2F%2Fmashable.com%2F2014%2F08%2F27%2Faustralia-retail-evolution-lab-aopen-shopping%2F"
cat_links = get_tweets(url)

谢谢, 是的

【问题讨论】:

  • 一个 JavaScript 解释器。
  • @IgnacioVazquez-Abrams 谢谢。这对我来说有点新,你能提供更多信息吗?非常感谢。
  • JavaScript 是一种由所有常见浏览器实现的客户端编程语言。它可以操作服务器返回的 HTML,也可以执行异步请求,允许它在不中断当前页面的情况下检索数据。这两件事在这里都发生过,也就是说直接从服务器获取的 HTML 和浏览器当前包含的 HTML 不匹配。
  • 或者你可以使用this link
  • 使用浏览器的控制台查看相关的ajax请求。

标签: python html web-scraping urllib


【解决方案1】:

问题是results div 的内容充满了额外的 HTTP 调用和在浏览器端执行的 javascript 代码。 urllib 只“看到”不包含您需要的数据的初始 HTML 页面。

一种选择是遵循@Himal 的建议并模拟对trackbacks.js 的基础请求,该请求通过推文发送数据。结果是 JSON 格式,您可以使用标准库附带的json 模块load()

import json
import urllib2

url = 'http://otter.topsy.com/trackbacks.js?url=http%3A%2F%2Fmashable.com%2F2014%2F08%2F27%2Faustralia-retail-evolution-lab-aopen-shopping%2F&infonly=0&call_timestamp=1411090809443&apikey=09C43A9B270A470B8EB8F2946A9369F3'
data = json.load(urllib2.urlopen(url))
for tweet in data['response']['list']:
    print tweet['permalink_url']

打印:

http://twitter.com/Evonomie/status/512179917610835968
http://twitter.com/abs_office/status/512054653723619329
http://twitter.com/TKE_Global/status/511523709677756416
http://twitter.com/trevinocreativo/status/510216232122200064
http://twitter.com/TomCrouser/status/509730668814028800
http://twitter.com/Evonomie/status/509703168062922753
http://twitter.com/peterchaly/status/509592878491136000
http://twitter.com/chandagarwala/status/509540405411840000
http://twitter.com/Ayjay4650/status/509517948747526144
http://twitter.com/Marketingccc/status/509131671900536832

这是“走向金属”选项。


否则,您可以采用“高级”方法,而不必担心幕后发生的事情。让真正的浏览器加载您将通过selenium WebDriver与之交互的页面:

from selenium import webdriver

driver = webdriver.Chrome()  # can be Firefox(), PhantomJS() and more
driver.get("http://topsy.com/trackback?url=http%3A%2F%2Fmashable.com%2F2014%2F08%2F27%2Faustralia-retail-evolution-lab-aopen-shopping%2F")

for tweet in driver.find_elements_by_class_name('result-tweet'):
    print tweet.find_element_by_xpath('.//div[@class="media-body"]//ul[@class="inline"]/li//a').get_attribute('href')

driver.close()

打印:

http://twitter.com/Evonomie/status/512179917610835968
http://twitter.com/abs_office/status/512054653723619329
http://twitter.com/TKE_Global/status/511523709677756416
http://twitter.com/trevinocreativo/status/510216232122200064
http://twitter.com/TomCrouser/status/509730668814028800
http://twitter.com/Evonomie/status/509703168062922753
http://twitter.com/peterchaly/status/509592878491136000
http://twitter.com/chandagarwala/status/509540405411840000
http://twitter.com/Ayjay4650/status/509517948747526144
http://twitter.com/Marketingccc/status/509131671900536832

这是您可以扩展第二个选项以在分页后获取所有推文的方式:

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

BASE_URL = 'http://topsy.com/trackback?url=http%3A%2F%2Fmashable.com%2F2014%2F08%2F27%2Faustralia-retail-evolution-lab-aopen-shopping%2F&offset={offset}'

driver = webdriver.Chrome()

# get tweets count
driver.get('http://topsy.com/trackback?url=http%3A%2F%2Fmashable.com%2F2014%2F08%2F27%2Faustralia-retail-evolution-lab-aopen-shopping%2F')
tweets_count = int(driver.find_element_by_xpath('//li[@data-name="all"]/a/span').text)

for x in xrange(0, tweets_count, 10):
    driver.get(BASE_URL.format(offset=x))

    # page header appears in case no more tweets found
    try:
        driver.find_element_by_xpath('//div[@class="page-header"]/h3')
    except NoSuchElementException:
        pass
    else:
        break

    # wait for results
    WebDriverWait(driver, 5).until(
        EC.presence_of_element_located((By.ID, "results"))
    )

    # get tweets
    for tweet in driver.find_elements_by_class_name('result-tweet'):
        print tweet.find_element_by_xpath('.//div[@class="media-body"]//ul[@class="inline"]/li//a').get_attribute('href')

driver.close()

【讨论】:

  • 非常感谢!如果我有任何问题,我会详细介绍您的答案并回复您。干杯
  • 我尝试了这两个选项,它们都在工作,非常感谢。如果可能,我有 2 个问题:1)对于选项 1,我怎么知道我需要使用什么链接来获取基础请求?换句话说,“otter.topsy.com/…”从何而来? 2) 如您所见,网页仅返回 10 个结果。如果我想提取所有结果,我该怎么办?谢谢,
  • @ybb 当然,1) 我刚刚探索了浏览器 (chrome) 开发人员工具中的“网络”选项卡。 2)更新了答案。希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 2020-06-17
  • 1970-01-01
  • 2020-09-30
  • 2014-06-14
  • 1970-01-01
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多