python简单爬虫实例7之使用selenium通过标签抓取贴吧特定内容并保存

本次使用selenium模拟浏览器,并提取数据。

任务:针对百度贴吧,根据标签定位特定内容,并且提取帖子名称、作者、回复数,并且自动点击下一步

1.selenium的安装与使用:

             第一步:在python环境中安装selenium,该过程可以参考我的一个帖子https://blog.csdn.net/RHJlife/article/details/87624520安装BeautifulSoup的过程。

            执行代码为:

pip install selenium

             第二步:安装谷歌浏览器的驱动程序。

具体如下过程:

首先查看自己谷歌浏览器版本:

    

可以看得出,我们版本为72.0.3626.109

其次,百度搜索驱动:

①百度搜索:chromedriver打开官网即可

②网址:http://npm.taobao.org/mirrors/chromedriver/

关于驱动的选择:其中有一些特殊版本号

如图:

如果是这些版本号(一模一样)就直接下载对应的版本,否则我们在

这些中选择对应范围。例如,我打开2.46选择notes.txt进行查看,

可以发现2.46对应版本为v71-73,而我们的为72版本,正好合适,根据自己的系统选择对应驱动即可。

最后,我们要使用下载好的驱动:

①可以将下载好的驱动放到编写的py文件目录下,直接使用browser = webdriver.Chrome()即可(该方法我运行不起来emmm)

②编程中使用browser = webdriver.Chrome(path),path为驱动的文件目录(本次编程使用该方法)

2.编程过程:

上次写完抓取特定的贴吧内容后,我们将其进行保存,但是保存过程中发现了很多问题。

遇到的困难:

                   第一:爬虫根据简单界面写的,当我们爬取某些大型贴吧时,会产生广告,关键是广告有标题,有回复数量为0但是没有作者,但是提取作者时会发生异常。

                   第二:提取某些属性时使用class无法提取到是因为知识量不足导致的。

解决方案:对于广告这一问题,我们使用异常来进行解决,当遇到无作者帖子时,我们默认它为广告并且取消本次抓取;某些标签具有class="a b c"这种形式时是同时具有三个class属性,并非是它具有的属性是a b c,当我们定位时,可以选择任意一个进行定位,而非直接粘贴a b c属性进行定位。

代码如下(已优化):

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import sqlite3
import os
db_file = 'tieba.db'
def jingdong(browser,x):
    save_list = []
    url = 'https://tieba.baidu.com/index.html'
    browser.get(url)
    input = browser.find_element_by_id('wd1')
    input.send_keys(x)
    input.send_keys('\n')
    while True:
        #该异常主要解决两个问题:第一个问题是浏览器加载速度慢于python执行速度导致的错误,第二个是不存在该贴吧的问题。
        try:
            #设置等待
            wait = WebDriverWait(browser, 10)
            #等待id=thread_list的内容加载完成后在进行下一步,或者超出十秒后
            goods_list = wait.until(EC.presence_of_element_located((By.ID, 'thread_list')))
            time.sleep(1)
            #提取所有的帖子
            ls_li = goods_list.find_elements_by_class_name('t_con')
            #遍历提取的帖子们,每个帖子提取
            for li in ls_li:
                save = {}
                num = li.find_element_by_class_name('threadlist_rep_num')
                name = li.find_element_by_class_name('threadlist_title')
                #如果提取作者失败,则认为该处内容为广告
                try:
                    people = li.find_element_by_class_name('frs-author-name-wrap')
                except:
                    continue
                #提取个人信息并保存
                save['name'] = name.text
                save['num'] = num.text
                save['people'] = people.text
                save_list.append(save)
            next = browser.find_element_by_class_name('next')
            url = next.get_attribute('href')
            if not url:
                break
            # 调用页面中的JS 进入下一页
            js='window.location.href = '+"'"+url+"'"
            browser.execute_script(js)
            count=0
        except:
            #如果发送异常,等待一秒,让浏览器加载
            time.sleep(1)
            count=count+1
            #如果连续五次异常,默认该贴吧不存在,退出该程序;同时如果加载过长也会触发该条件
            if(count>5):
                break
    return save_list


def create_table():
    # 1. 连接数据库
    conn = sqlite3.connect(db_file)

    # 2. 创建执行对象
    cursor = conn.cursor()

    # 3. 执行SQL语句
    cursor.execute('''
        create table movie(
            id integer primary key autoincrement,
            name text,
            num text,
            people text
        )
    ''')

    # 4. 提交操作, 对于可以修改数据库内容的操作, 必须要提交
    conn.commit()

    # 5. 关闭连接

def save(movie):
    # 1. 连接
    conn = sqlite3.connect(db_file)

    # 2. 创建执行对象
    cursor = conn.cursor()

    # 3. 执行SQL语句
    cursor.execute('''
        insert into movie 
        (name, num, people)
        values
        (?, ?, ?)
    ''', (movie.get('name'), movie.get('num'), movie.get('people') ))
    print(movie.get('name'), movie.get('num'), movie.get('people'))

    # 4. 提交
    conn.commit()

    # 5. 关闭
    conn.close()


if __name__=='__main__':
    x = input('请输入内容:')
    #测试写的固定内容
    #x='罗小黑战记妖灵簿'
    path='/Users/ren/PycharmProjects/抓取异步操作/chromedriver'
    browser = webdriver.Chrome(path)
    time.sleep(2)

    sa=jingdong(browser,x)
    if not os.path.exists(db_file):
        create_table()
    for s in sa:
        save(s)
    time.sleep(5)
    browser.close()

总结:运行代码过程,发现有时候运行几个页面就异常结束,有时候运行几十个页面就会异常,完整运行下来极少,最后在老师的帮助下成功解决,主要牵扯一个浏览器加载速度低于python代码执行的速度。简单举例就是,我打开了第一页并且完成了数据的收集,我跳到第二页,然后数据并没有加载完成,但是我已经要抓取数据了,可能之前因为没有完全加载,我抓的大框架数据是第一页的,加载完成后,抓取的数据消失了,我还要在那些数据时进行提取。同时一个解决方案就是,加载后增加延时,但是这样会让加载很快的界面也会花费时间去等待延时,而增加异常就可以完美解决该问题,只有发生异常时,再延时一秒,然后重新进行抓取操作。

后期发现该解决方案,如果碰到不存在的贴吧会发生死循环现象,所以增加连续五次异常,则认为该贴吧不存在,即可解决问题需求,以上代码为最终完善后代码。

猜你喜欢

转载自blog.csdn.net/RHJlife/article/details/87819058