使用selenium的爬虫实践。
爬取京东网的手机数据,robots协议
本次就不讲解思路了,而是将源代码详细说明一下。
1、import
#webdriver用于生成浏览器
from selenium import webdriver
#Options用于初始化浏览器
from selenium.webdriver.chrome.options import Options
#用于搜索栏输入后确定。
from selenium.webdriver.common.keys import Keys
#pymysql是MySQL的接口
import pymysql.cursors
#用于计算本次爬虫用时/非必要/
import datetime
#用于selenium的强制等待
import time
这里需要解释的仅selenium的强制等待。
在浏览器加载网页的过程中,网页的有些元素时常会有延迟的现象,在 HTML 元素还没有准备好的情况下去操作这个 HTML 元素必然会出现错误,这个时候 Selenium 需要等待HTML 元素。
而强制等待就是通过time.sleep()来做到的,因为无论是否加载完,都要休眠那么久,因而叫做‘强制等待’。
这样做缺点很多,下次开博详讲。
2、class Spider:
爬虫源码创建了一个爬虫类。如下简略:
class Spider:
#浏览器的头
headers={"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"}
#初始化
def startUp(self, url, key):...
#关闭爬虫
def closeUp(self):...
#数据插入数据库
def insertDB(self, mNo,mPrice, mNote):...
#主要过程
def processSpider(self,page=0):...
#执行爬虫,即主程序
def executeSpider(self, url, key):
2.1 startUp
初始化函数,初始化了浏览器,某些变量和数据库,以及执行搜索命令。
def startUp(self, url, key):
# Initializing Chrome browser
chrome_options = Options()
#下面两项为无头与禁止gpu加速;
#--headless比较重要,执行selenium时不会弹出浏览器窗口
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
#创建Chrome浏览器
self.driver = webdriver.Chrome(chrome_options=chrome_options)#
# Initializing variables
self.No = 0
数据库的初始化
print('opened DB')
try:
#连接数据库,参数有host,port,user,passwd,db和charset,详细请阅读MySQL的手册
self.con = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="", db='db1',charset="utf8")
#创建游标
self.cursor = self.con.cursor(pymysql.cursors.DictCursor)
#很重要的一件事是对已存在的数据库表来执行插入是很麻烦的,所有初始化时删除可能存在的表,重新创建。
#删除表
try:
self.cursor.execute("drop table phones")
except Exception as err:
print(err)
#创建表
try:
sql = """
create table phones(No varchar(32) primary key,Price varchar(32),Note text)"""
self.cursor.execute(sql)
except Exception as err:
print(err)
#变量的初始化,opened表示数据库是否打开,count是计数,执行了多少次插入语句
self.opened = True
self.count = 0
except Exception as err:
print(err)
self.opened = False
执行搜索命令
#访问url,获得源代码
self.driver.get(url)
#这里是selenium是使用元素方法,输入与确认等
keyInput = self.driver.find_element_by_id("key")
keyInput.send_keys(key)
keyInput.send_keys(Keys.ENTER)
以上详细指南,在博文2.1与2.2
2.2 closeUp
关闭数据库,并输出爬取数据数量。
def closeUp(self):
if self.opened:
self.con.commit()
self.con.close()
self.opened = False
print("closed")
print("总共爬取", self.count, "条数据")
2.3 insertDB
数据库插入数据语句。每执行一次,count+1
def insertDB(self, mNo,mPrice, mNote):
try:
if self.opened:
sql = "insert into phones(No,Price,Note) values (%s,%s,%s)"
self.cursor.execute(sql,(mNo,mPrice, mNote))
self.count+=1
except Exception as err:
print(err)
2.4 progressSpider
这个模块主要是Spider执行的具体内容
扫描二维码关注公众号,回复:
8680331 查看本文章
def processSpider(self,page=0):
try:
#强制等待1秒
time.sleep(1)
print(self.driver.current_url)
观察京东搜索页的源代码,可以发现所有商品的数据都在属性为id='J_goodsList的标签div下,其下每个li就是一个商品数据。
selenium查找元素的具体语法。
lis=self.driver.find_elements_by_xpath("//div[@id='J_goodsList']//li[@class='gl-item']")
for li in lis:
#同理很容易找到所需要数据的位置,执行xpath和text()得到字符串内容
price = li.find_element_by_xpath(".//div[@class='p-price']//i").text
note = li.find_element_by_xpath(".//div[@class='p-name p-name-type-2']//em").text
#观察发现有部分数据标题前是‘京品手机’等无关数据,通过if语句剔除。
if note[0:2]=='京品':note=note[5:]
if '】' in note:note=note[note.index('】')+1:]
#给每一条数据编号
self.No = self.No + 1
no = str(self.No)
while len(no) < 6:
no = "0" + no
#输出
print('%-8s %-8s %s'%(no,price,note))
#插入
self.insertDB(no, price, note)
循环插入所有数据后,即执行翻页的命令。a[@class=‘pn-next disabled’],这个标签是最后一页,找不到即执行nextPage = self.driver.find_element_by_xpath("//span[@class='p-num']//a[@class='pn-next']")
,找到后执行nextPage.click()
,点击翻页。递归执行self.processSpider(page)
try:
self.driver.find_element_by_xpath("//span[@class='p-num']//a[@class='pn-next disabled']")
except:
nextPage = self.driver.find_element_by_xpath("//span[@class='p-num']//a[@class='pn-next']")
nextPage.click()
#当前页面数+1,以下if语句用来限制翻页数。
page+=1
if page==Page:return
self.processSpider(page)
except Exception as err:
print(err)
2.5 executeSpider
def executeSpider(self, url):
starttime = datetime.datetime.now()
print("Spider starting......")
key=input('请输入要搜索的内容:')
Page=int(input('请输入要爬取的页数,如若不限制,请输入-1:'))
self.startUp(url, key)
self.processSpider(Page)
self.closeUp()
print("Spider completed......")
endtime = datetime.datetime.now()
elapsed = (endtime - starttime).seconds
print("Total ", elapsed, " seconds elapsed")
3、主程序
if __name__=='__main__':
url = "http://www.jd.com"
spider = Spider()
spider.executeSpider(url)
4、完整源代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:LingInHeart
# Time: 2019/12/21
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import pymysql.cursors
import datetime
from selenium.webdriver.common.keys import Keys
import time
class Spider:
def startUp(self, url, key):
# Initializing Chrome browser
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
self.driver = webdriver.Chrome(chrome_options=chrome_options)#
# Initializing variables
self.No = 0
# Initializing database
print('opened')
try:
self.con = pymysql.connect()
self.cursor = self.con.cursor(pymysql.cursors.DictCursor)
try:
self.cursor.execute("drop table phones")
except Exception as err:
print(err)
try:
sql = """
create table phones(No varchar(32) primary key,Price varchar(32),Note text)"""
self.cursor.execute(sql)
except Exception as err:
print(err)
# self.cursor.execute("delete from books")
self.opened = True
self.count = 0
except Exception as err:
print(err)
self.opened = False
self.driver.get(url)
keyInput = self.driver.find_element_by_id("key")
keyInput.send_keys(key)
keyInput.send_keys(Keys.ENTER)
def closeUp(self):
if self.opened:
self.con.commit()
self.con.close()
self.opened = False
print("closed")
print("总共爬取", self.count, "条数据")
def insertDB(self, mNo,mPrice, mNote):
try:
if self.opened:
sql = "insert into phones(No,Price,Note) values (%s,%s,%s)"
self.cursor.execute(sql,(mNo,mPrice, mNote))
self.count+=1
except Exception as err:
print(err)
def processSpider(self,Page,page=0):
try:
time.sleep(1)
print(self.driver.current_url)
lis=self.driver.find_elements_by_xpath("//div[@id='J_goodsList']//li[@class='gl-item']")
for li in lis:
price = li.find_element_by_xpath(".//div[@class='p-price']//i").text
note = li.find_element_by_xpath(".//div[@class='p-name p-name-type-2']//em").text
if note[0:2]=='京品':note=note[5:]
if '】' in note:note=note[note.index('】')+1:]
self.No = self.No + 1
no = str(self.No)
while len(no) < 6:
no = "0" + no
print('%-8s %-8s %s'%(no,price,note))
self.insertDB(no, price, note)
try:
self.driver.find_element_by_xpath("//span[@class='p-num']//a[@class='pn-next disabled']")
except:
nextPage = self.driver.find_element_by_xpath("//span[@class='p-num']//a[@class='pn-next']")
nextPage.click()
page+=1
if page==Page:return
self.processSpider(Page,page)
except Exception as err:
print(err)
def executeSpider(self, url):
starttime = datetime.datetime.now()
print("Spider starting......")
key=input('请输入要搜索的内容:')
Page=int(input('请输入要爬取的页数,如若不限制,请输入-1:'))
self.startUp(url, key)
self.processSpider(Page)
self.closeUp()
print("Spider completed......")
endtime = datetime.datetime.now()
elapsed = (endtime - starttime).seconds
print("Total ", elapsed, " seconds elapsed")
if __name__=='__main__':
url = "http://www.jd.com"
spider = Spider()
spider.executeSpider(url)