用Python写爬虫入门篇(三)
简介
最近在学习python,这几篇博文用于个人记录总结,不正之处还望大佬指出。(适合学习过python的同学)
用Python写爬虫入门篇(一)
用Python写爬虫入门篇(二)
用Python写爬虫入门篇(三)
我的运行环境
系统版本:Windows10
Python版本:Python3.7
IDE:IDEA(因为平时主要用JAVA就没安PyCharm了)
(安装适合自己的环境即可)
动态网页问题
当我们查看源码写爬虫时,有时会发现我们网页中的数据有的并不在源代码中(点击“查看网页源代码(V)”找不到相应元素),为什么呢,因为那是动态网页。和静态网页不同,动态网页显示的内容可以随着时间、环境或者数据库操作的结果而发生改变。那么如何爬取动态网页呢。需要用到今天的新技能:
浏览器(Chrome+Chromedriver)+Selenium+Python
技能介绍
浏览器:其实主流浏览器(只要有相应driver)都能完成我们的任务(模拟正常访问),因为小编用的Chrome,所以以下面的教程就用Chrome写了,需要下载Chrome浏览器和 相应版本的driver(下载地址)
Selenium:它是一个自动化测试工具。它支持各种浏览器,包括 Chrome,Safari,Firefox 等主流界面式浏览器,可用Python驱动执行模拟正常的访问行为,我们需要安装 Python 的 Selenium 库(pip install selenium),用Selenium可执行页面交互,填充表单,Cookies处理,元素选取等一系列功能,具体功能请查看官网Selenium with Python。
原理:用浏览器解析动态网页,再从相应网页提取有用数据。
爬取思路
- 确定爬取地址与目标数据
- 用(Chrome+Chromedriver)+Selenium模拟正常访问
- 用BeautifulSoup工具分析页面
- 最后将数据存入相应文件夹
爬取实例:
接下来让我们来爬一爬好看的电影吧 :
https://movie.douban.com/tag/#/?sort=S&range=0,10&tags=电影
以上述URL为例,在此网页,右键点击“查看源代码(V)”
我们再其中查找电影“霸王别姬”元素,可是查找不到,这时我们怎么查找此元素呢
在原网页,右键点击“检查(N)”,然后按下(CTRL+F)在检查中查找我们想要的元素,这时就可以查找了(例如:霸王别姬)
找到动态网页中我们的目标后,我们再来找到我们想要爬取的内容(电影海报,电影名,评分)
由上图我们可知,所有的电影内容都包含在class="item"的<a>标签中,电影海报在<a>标签中的<span>的src属性中,电影名则在alt属性中,而评分在另一个<span>标签中故我们可以写出如下关键代码:
all_a = BeautifulSoup(driver.page_source,"lxml").find_all("a",class_="item")
for a in all_a:
movie_name = a.img["alt"]#电影名称
movie_img_url = a.img["src"]#电影图片地址
movie_score = a.find("span",class_="rate").string#电影评分
(更多BeautifulSoup包用法请查看 Beautiful Soup 4.4.0 文档)
找到元素了,那么我们怎么实现加载更多呢?对的,没错,用Selenium模拟我们的行为,
我们用刚学会的"检查"方法查找页面的“加载更多”按键,如图:同样,以下是关键代码
webelement_a = driver.find_element_by_id(id_="app").find_element_by_xpath("div/div/a")# selenium查找元素和XPath路径
webelement_a.click()
(find_element_by_id和find_element_by_xpath只是众多查找方式中的两种,具体请查看官网Selenium with Python)
详细代码如下
(其它的就不过多解释了,也有相应注释)
from selenium import webdriver
from bs4 import BeautifulSoup
import requests
import os
import time
class MoviesCover():
def __init__(self):
self.web_url = "https://movie.douban.com/tag/#/?sort=S&range=0,10&tags=%E7%94%B5%E5%BD%B1"#目标网页
self.folder_path ="D:\IMGFile" #存储数据的本地地址,改成自己的地址
def save_img(self,url,file_name):
img = self.request(url)
print('开始保存图片')
f = open(file_name,"ab")
f.write(img.content)
print('图片保存成功!')
f.close()
def scroll_down(self, driver, times):
for i in range(times):
print("第", str(i + 1), "次等待网页加载......")
time.sleep(5) #根据网速决定时间,当前为5s,网速慢则等待时间长
print("开始执行第", str(i + 1),"次加载操作")
webelement_a = driver.find_element_by_id(id_="app").find_element_by_xpath("div/div/a")# selenium查找元素和XPath路径
webelement_a.click()#找到对应按扭后用模拟浏览器点击它,以实现翻页(其它众多功能请查看官网)
print("第", str(i + 1), "次下拉操作执行完毕")
def mkdir(self,path):
path = path.strip()
isExists = os.path.exists(path)
if not isExists:
print('创建名字叫做', path, '的文件夹')
os.makedirs(path)
print('创建成功!')
return True
else:
print(path, '文件夹已经存在了,不再创建')
return False
def request(self,url):
r = requests.get(url)
return r
def get_files(self,path):
pic_names = os.listdir(path)
return pic_names
def crawler(self):
print("start!")
driver = webdriver.Chrome("D:\Program Files\Python37\Tools\ChromeDriver\chromedriver.exe") #Chrome浏览器的本地驱动地址,也可以把该地址加到环境变量,改成自己的地址
driver.get(self.web_url)
self.mkdir(self.folder_path) # 创建文件夹
print('开始切换文件夹')
os.chdir(self.folder_path) # 切换路径至上面创建的文件夹
self.scroll_down(driver=driver, times=10)#times是向后翻页的次数
file_names = self.get_files(self.folder_path)
all_a = BeautifulSoup(driver.page_source,"lxml").find_all("a",class_="item")
for a in all_a:
movie_name = a.img["alt"]#电影名称
print(movie_name)
movie_img_url = a.img["src"]#电影图片地址
print(movie_img_url)
movie_score = a.find("span",class_="rate").string#电影评分
print(movie_score)
movie_filename = movie_name + "_score_" + movie_score + ".jpg"
movie_filename = movie_filename.replace(" ","_") #替换名称中的特殊字符为"_",不然有些不规范的名称会让程序报错
movie_filename = movie_filename.replace("/","_")
movie_filename = movie_filename.replace('"',"_")
if movie_name in file_names:
print('电影已经存在,不再重新下载')
else:
self.save_img(movie_img_url, movie_filename)
movies_cover = MoviesCover()
movies_cover.crawler()#执行
爬取结果
这几篇爬虫看完后可以自己写几个小爬虫了,但在爬取大项目时,速度会是大问题,因为BeautifulSoup是用Python编写的,本身速度会受影响,所以接下来可能会写关于Scrapy框架的内容,先这样吧,Bye~