豆瓣爬虫
豆瓣书目齐全,评分客观,美中不足的是搜索结果不能筛选,决定自己做个小程序用来选书。
只简单提取书名+评分+评价人数+书本的简要信息,后续放到Excel表格里做进一步筛选
前置:安装第三方库selenium、lxml;安装chrome和配套的chromedriver
chromedriver各版本的下载地址:https://sites.google.com/a/chromium.org/chromedriver/downloads
.
小技巧:借助浏览器获得path路径
- 【F12】调出控制台
- 【Ctrl+Shift+C】单击选中要提取的元素
- 在控制台元素位置,调出右键菜单——Copy——选择Xpath/full Xpath
.
搜索窗口
完整代码
from tkinter import *
def search_douban(key): #模拟用chrome浏览器在豆瓣搜索关键词
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
browser = webdriver.Chrome() #打开浏览器
browser.get('https://book.douban.com/') #打开豆瓣读书主页
element = browser.find_element_by_id('inp-query') #定位到搜索框
element.send_keys(key) #输入关键词
element.send_keys(Keys.ENTER) #回车
return browser
def get_row(frame): #从一本书的结果中提取各元素
paths = ['.//div[1]/a/text()', #标题
'.//div/div[2]/span[2]/text()', #评分
'.//div/div[2]/span[3]/text()', #评价人数
'.//div/div[3]/text()'] #书本的简要信息
row = [frame.xpath(path) for path in paths]
for i in range(4): row[i] = '' if row[i] == [] else row[i][0] #空列表转空字符串,非空列表取第一个元素
row[2] = row[2].replace('(', '').replace('人评价)', '') #整理评价人数
row = '\t'.join(row) #用【\t】连接各元素
return row #返回字符串
def page_to_row(browser):
from lxml import etree
html = browser.page_source #获得整个页面
html = etree.HTML(html) #把页面做成etree
path = '//*[@id="root"]/div/div[2]/div[1]/div[1]/div[*]' #搜索结果的path合集
frames = html.xpath(path) #一页搜索结果合集
rows = [get_row(frame) for frame in frames] #逐本书提取信息,整页搜索结果放在一个列表里
rows = [row for row in rows if row != ',,,'] #排除空白的搜索结果
rows = "\n".join(rows) #不同的搜索结果,用换行符连接成字符串
return rows #返回字符串
def my_loop(keyword, browser):
while True:
rows = page_to_row(browser) #获取第一页的搜索结果,处理成字符串
file = open(f'{keyword}.txt', 'a') #打开以关键词命名的文件,把搜索结果写进去
file.write(rows)
file.close()
element = browser.find_elements_by_class_name('next') #在chrome浏览器点击下一页,依次循环
try: element[0].click() #直到没有【下一页】可点时,退出while循环
except: break
def create_win():
def command1():
keyword = entry.get() #从entry框获取关键词
browser = search_douban(keyword) #模拟浏览器在豆瓣搜索关键词
my_loop(keyword, browser) #循环:获取、输出当页内容——下一页
win = Tk() #创建窗口、单行文本框、按钮
entry = Entry(win)
entry.pack(side=LEFT)
Button(win, text="确认", width=10, command=command1).pack(side=LEFT)
create_win()