本次使用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代码执行的速度。简单举例就是,我打开了第一页并且完成了数据的收集,我跳到第二页,然后数据并没有加载完成,但是我已经要抓取数据了,可能之前因为没有完全加载,我抓的大框架数据是第一页的,加载完成后,抓取的数据消失了,我还要在那些数据时进行提取。同时一个解决方案就是,加载后增加延时,但是这样会让加载很快的界面也会花费时间去等待延时,而增加异常就可以完美解决该问题,只有发生异常时,再延时一秒,然后重新进行抓取操作。
后期发现该解决方案,如果碰到不存在的贴吧会发生死循环现象,所以增加连续五次异常,则认为该贴吧不存在,即可解决问题需求,以上代码为最终完善后代码。