【问题标题】:Scrape websites with infinite scrolling using selenium and beautifulsoup return repeated elements使用 selenium 和 beautifulsoup 抓取具有无限滚动的网站返回重复元素
【发布时间】:2017-12-05 08:22:23
【问题描述】:

所以我有使用 Selenium 和 BeautifulSoup 来抓取这个网站的脚本: 'http://m.1688.com/page/offerlist.htmlspm=a26g8.7664812.0.0.R19GYe&memberId=zhtiezhi&sortType=tradenumdown'

但我的脚本继续打印页面的前 8 个元素,而忽略滚动时出现的内容。这是脚本:

# -*- coding: utf-8 -*-
from urllib import urlopen
from bs4 import BeautifulSoup as BS
import unicodecsv as ucsv
import re 
from selenium import webdriver
import time 

with open('list1.csv','wb') as f:
w = ucsv.writer(f, encoding='utf-8-sig')

driver = 
webdriver.Chrome('C:\Users\V\Desktop\PY\web_scrape\chromedriver.exe')
base_url = 'http://m.1688.com/page/offerlist.html?
spm=a26g8.7664812.0.0.R19GYe&memberId=zhtiezhi&sortType=tradenumdown'
driver.get(base_url)
pageSource = driver.page_source
lst = []
for n in range(10): 
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    soup = BS(pageSource, 'lxml')
    container = soup.find('div', {'class' : 'container'})
    items = container.findAll('div', {'class' : 'item-inner'})
    for item in items:
        title = item.find('div', {'class' : 'item-price'}).text
        title_ = ''.join(i for i in title if ord(i) < 128  if i != '\n')
        lst.append(title_)
    print lst
    time.sleep(5)

每个滚动的输出是:

[u'0.21', u'0.45', u'1.10', u'3.60', u'2.20', u'6.80', u'1.40', u'3.00']
[u'0.21', u'0.45', u'1.10', u'3.60', u'2.20', u'6.80', u'1.40', u'3.00', u'0.21', u'0.45', u'1.10', u'3.60', u'2.20', u'6.80', u'1.40', u'3.00']
[u'0.21', u'0.45', u'1.10', u'3.60', u'2.20', u'6.80', u'1.40', u'3.00', u'0.21', u'0.45', u'1.10', u'3.60', u'2.20', u'6.80', u'1.40', u'3.00', u'0.21', u'0.45', u'1.10', u'3.60', u'2.20', u'6.80', u'1.40', u'3.00']

第一个滚动列表有 8 个元素,第二个滚动列表有 16 个元素,额外的 8 个元素从第一个滚动重复。其余的卷轴也会发生同样的事情。 因此,即使我使用 selenium 滚动站点,脚本也只返回 8 个元素,但我希望它在滚动时打印出所有元素。如果你们能给我一些建议,我将不胜感激。

【问题讨论】:

    标签: python selenium web-scraping beautifulsoup


    【解决方案1】:

    问题出在这部分:

    items = container.findAll('div', {'class' : 'item-inner'})
        for item in items:
            title = item.find('div', {'class' : 'item-price'}).text
            title_ = ''.join(i for i in title if ord(i) < 128  if i != '\n')
            lst.append(title_)
    

    每次“滚动”items 对象时都会变大一个块,因为当您滚动时,上方的内容不会消失。 您需要从items 中删除第一个n-1 items 以避免重复。

    【讨论】:

    • 这不是问题,因为如果你看一下列表,最后一个列表包含相同的 8 个元素,如 lst3 = 3*lst1,没有任何变化。
    • 但我不知道什么时候停止滚动,一定有一个限制。
    • 嗯,取决于页面...例如,如果您开始滚动 VK.com 的提要页面,如果您有很多朋友,那么提要页面将持续很长时间=)这也取决于如何你想要很多内容。这里的好处是您可以手动限制迭代并获得所需的尽可能多的内容。您实际上可以在 while 上替换 for 循环,并且有一天会到达页面内容的末尾=)
    • 我理解这个概念,但我不知道如果脚本能够滚动,是否会引发某种错误。
    • 您可以使用try - except 子句预测任何错误,并在这种情况下设置替代脚本行为。
    【解决方案2】:

    有两种可能:

    1. 让无限滚动结束,然后获取数据;
    2. 每次内容重新加载后,您都可以将已有数据与新数据进行比较,然后将其添加到列表中。

    【讨论】:

    • 无限滚动后页面变得如此沉重,以至于崩溃并失败。
    【解决方案3】:

    我已经找到了问题的答案,通过将 pageSource 放入循环中,而不是将 Chrome 隐藏在任务栏中,您必须打开它,或者您可以使用 PhantomJS 而不是 Chrome 驱动程序。

    for n in range(10):
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(2)
    pageSource = drive.page_source
    soup = BS(pageSource, 'lxml')
    container = soup.find('div', {'class' : 'container'})
    items = container.findAll('div', {'class' : 'item-inner'})
    for item in items:
        title = item.find('div', {'class' : 'item-price'}).text
        title_ = ''.join(i for i in title if ord(i) < 128  if i != '\n')
        lst.append(title_)
    print len(lst)
    

    现在输出会改变,而不是

    8
    8
    8
    8
    

    它会打印出来

    16
    20
    28
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      • 2021-12-04
      • 2019-09-29
      • 1970-01-01
      • 2021-01-21
      • 2012-09-13
      • 2014-05-07
      相关资源
      最近更新 更多