【问题标题】:Scraping a forum: cannot scrape posts that have a table within them抓取论坛:无法抓取其中包含表格的帖子
【发布时间】:2016-07-08 19:04:46
【问题描述】:

我的第一个爬虫快写完了!

但是,我遇到了一个障碍:我似乎无法获取包含表格的帖子的内容(换句话说,帖子引用了另一个帖子)。

这是从汤对象中提取帖子内容的代码。它工作得很好:

    def getPost_contents(soup0bj):

        try:
          soup0bj = (soup0bj)
          post_contents = []

          for content in soup0bj.findAll('', {'class' : 'post_content'}, recursive = 'True'):
             post_contents.append(content.text.strip())

         ...#Error management

         return (post_contents)

以下是我需要抓取的示例(以黄色突出显示):

Problem post

(网址,以防万一:http://forum.doctissimo.fr/sante/diabete/savoir-diabetique-sujet_170840_1.htm#t657906

如何获取我突出显示的内容?为什么我当前的 getPostcontents 函数在这个特定实例中不起作用?据我所见,字符串仍在 div class=post_contents 下。

编辑编辑编辑

这就是我获得 BeautifulSoup 的方式:

    from bs4 import BeautifulSoup as Soup

    def getHTMLsoup(url):

       try:
          html = urlopen(url)
       ...#Error management

       try:
          soup0bj = Soup(html.read().decode('utf-8', 'replace'))
          time.sleep(5)
       ...#Error management

       return (soup0bj)

编辑2 编辑2 编辑2

这些是刮板的相关位:(对不起转储!)

    from bs4 import BeautifulSoup as Soup
    from urllib.request import urlopen, urlretrieve
    from urllib.error import HTTPError, URLError
    import time, re

    def getHTMLsoup(url):


       try:
          html = urlopen(url)

       except HTTPError as e:
          return None
          print('The server hosting{} is unavailable.'.format(url), '\n')
          print('Trying again in 10 minutes...','\n')
          time.sleep(600)
          getHTMLsoup(url)

       except URLError as e:
          return None 
          print('The webpage found at {} is unavailable.'.format(url),'\n')
          print('Trying again in 10 minutes...','\n')
          time.sleep(600)
          getHTMLsoup(url)

        try:
            soup0bj = Soup(html.read().decode('utf-8', 'replace'))
            time.sleep(5)

        except AttributeError as e:
          return None
          print("Ooops, {}'s HTML structure wasn't detected.".format(url),'\n')


        return soup0bj

    def getMessagetable(soup0bj):
       try:
          soup0bj = (soup0bj)
          messagetable = []

          for data in soup0bj.findAll('tr', {'class' : re.compile('message.*')}, recursive = 'True'):

       except AttributeError as e:
          print(' ')

       return (messagetable)

    def getTime_stamps(soup0bj):

       try:
          soup0bj = (soup0bj)
          time_stamps = []

          for stamp in soup0bj.findAll('span', {'class' : 'topic_posted'}):
        time_stamps.append(re.search('..\/..\/20..', stamp.text).group(0))

       except AttributeError as e:
          print('No time-stamps found. Moving on.','\n')

       return (time_stamps)

    def getHandles(soup0bj):

       try:
          soup0bj = (soup0bj)
          handles = []

          for handle in soup0bj.findAll('span', {'data-id_user' : re.compile('.*')}, limit = 1):
             handles.append(handle.text)

        except AttributeError as e:
           print("")

        return (handles)

    def getPost_contents(soup0bj):

       try:
          soup0bj = (soup0bj)
          post_contents = []

          for content in soup0bj.findAll('div', {'class' : 'post_content'}, recursive = 'True'):
             post_contents.append(content.text.strip())

       except AttributeError as e:
          print('Ooops, something has gone wrong!')

       return (post_contents)


    html = ('http://forum.doctissimo.fr/sante/diabete/savoir-diabetique-sujet_170840_1.htm')

    for soup in getHTMLsoup(html):
       for messagetable in getMessagetable(soup):

          print(getTime_stamps(messagetable),'\n')
          print(getHandles(messagetable),'\n')
          print(getPost_contents(messagetable),'\n') 

【问题讨论】:

  • 您当前的输出是多少?我看到这个帖子和其他帖子一样被提取。
  • 对我也有用,虽然它停留在前面的文本中
  • 嘿,谢谢你的提问!目前,它输出所有帖子,保存那些在 div class=post_contents 中有表格的帖子
  • 我的问题可能是什么?有什么猜测吗?
  • @Gabriel,Beautifulsoup 是什么版本,你是如何获得 html 的?

标签: python-3.x web-scraping beautifulsoup


【解决方案1】:

问题是你的解码,它不是utf-8,如果你删除"replace"你的代码会出错:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 253835: invalid continuation byte

数据似乎是 latin-1 编码的,解码为 latin-1 不会导致错误,但输出确实在某些部分看起来不正确,使用。

 html  = urlopen(r).read().decode("latin-1")

会起作用,但正如我提到的,你会得到奇怪的输出,例如:

"diabète en cas d'accident de la route ou malaise isolÊ ou autre ???" 

另一种选择是传递一个接受字符集标题:

from urllib.request import Request, urlopen
headers = {"accept-charset":"utf-8"}
r = Request("http://forum.doctissimo.fr/sante/diabete/savoir-diabetique-sujet_170840_1.htm#t657906",headers=headers)
html  =  urlopen(r).read()

我使用让它处理编码的请求得到了完全相同的编码问题,就像数据具有混合编码,一些 utf-8 和一些 latin-1。从请求返回的标头显示内容编码为 gzip 为:

 'Content-Encoding': 'gzip'

如果我们指定我们想要 gzip 和解码:

from urllib.request import Request, urlopen
headers = {"Accept-Encoding":"gzip"}
r = Request("http://forum.doctissimo.fr/sante/diabete/savoir-diabetique-sujet_170840_1.htm#t657906",headers=headers)
r = urlopen(r)

import gzip
gzipFile = gzip.GzipFile(fileobj=r)

print(gzipFile.read().decode("latin-1"))

我们在 utf-8 和 latin-1 中得到相同的奇怪输出解码。有趣的是,在 python2 中,请求和 urllib 都可以正常工作。

使用 chardet:

r = urlopen(r)
import chardet
print(chardet.detect(r.read()))

大约有 71% 的人相信它是 ISO-8859-2,但这又给出了同样糟糕的输出。

{'confidence': 0.711104254322944, 'encoding': 'ISO-8859-2'}

【讨论】:

  • 谢谢!您能否澄清一下“标题”和 urlopen(r).read() 在我的代码中的位置?我(还)不熟悉这种做事方式。
  • @Gabriel,就像我在答案中一样使用它们。
  • @Gabriel,别担心,你也看到奇怪的输出了吗?
  • 是的,只有当我要求它编码为 utf-8 时,我才明白。想知道在不同的地区是否与此有关。
  • @Gabriel,您没有看到它通过替换解码为 utf-8 的唯一原因可能是因为您丢失了它,您是否看到像 diabète 这样的输出?
猜你喜欢
  • 2017-07-22
  • 2016-12-09
  • 1970-01-01
  • 1970-01-01
  • 2014-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-23
相关资源
最近更新 更多