前几天学习了selenium,于是动手写了一个小爬虫,主要通过利用selenium然后对浏览器进行操作。
整个代码利用到的模块有以下:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException #超时的异常
from bs4 import BeautifulSoup
下面介绍一下写整个爬虫的过程,代码我会根据自己的理解进行详细的解析,当然如果我的理解错了,希望各位能够及时指出,毕竟我也只是初学者。
接下来按步骤来分解代码
第一步:进行初始化
所有的方法都是写在类里面的,因此我们第一步先初始化,要初始化的对象有两个,一个是webdriver,一个是WebDriverWait。
那么这两个是什么呢,一个是用来驱动浏览器的,一个是用来进行等待元素刷新的。
(这里提一下这个等待的过程。当我们打开一个页面的时候,假设页面还没有加载完成,这个时候可能会导致我们要定位的那个元素定位不到,从而报错,而WebDriverWait,解决了这个问题,我们可以给它规定一个时间,在这个时间范围内,我们会一直等待网页加载并同时不断的检查我们想要定位的元素是否已经被加载出来了,如果是,那么我们就继续执行下面的代码,否则超过了最长时间时,抛出异常。)
那么接下来用来初始化的函数长下面这样:
def __init__(self):
self.driver = webdriver.Chrome()
self.wait = WebDriverWait(self.driver,10) #self.driver是打开的浏览器,10是最长等待时间
第二步:打开淘宝网页,自动输入输入我们想要查找的商品
查找的方法长这样:
def search(self,shop = None): #商品名一开始为None,需要我们手动输入
print('开始搜索了')
self.driver.get('https://www.taobao.com') #打开淘宝网首页
try:
#判断我们要的搜索输入框是否加载完成
input = self.wait.until( #返回的对象应该是所要寻找的目标元素
EC.presence_of_element_located((By.CSS_SELECTOR,'#q')) #presence_of_element_located这个函数接收的参数是元组,表示检查某个元素是否在dom树里面,如果存在就返回这个元素
)
input.send_keys(u'{}'.format(shop)) #如果要定位的元素被加载出来了,那么执行下面的代码,这里是将shop的值自动输入搜索框
#判断搜索按钮是否加载完成
submit = self.wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR,'#J_TSearchForm > div.search-button > button')) #判断某个按钮是否可以点击,可以就返回这个按钮
)
submit.click() #点击按钮
except TimeoutException:
raise TimeoutException
我觉得还有一个地方需要说明一下,参数里面的By.CSS_SELECTOR是CSS属性选择器,后面跟的是CSS属性,该参数可以通过按F12,然后点击标签所在位置然后右键选择COPY,可以看到一个selector,点击复制然后粘贴就可以了。
下面的也是一样的道理
presence_of_element_located()接收的参数是一个元组,所以我们再里面还要加多一个括号。
第三步:开始进行信息的爬取
我在第二步输入的是python,因此我要爬取的信息有以下几个:
1.图片的链接 2.图书的价格 3.付款的人数 4.图书的名字 5.发货地
这里我们选择BeautifulSoup来获得这些信息,bs4是解析网页的神器,用的很爽。
那么解析网页的前提是我们要得到这个网页的源代码
怎么做呢,用driver.page_source就可以啦,是不是很简单。
所以爬取信息的方法长这样:
def get_response(self):
#判断当前的商品加载出来没有
self.wait.until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#mainsrp-itemlist .items .item')) #整一页的商品信息在这个id为#mainsrp-itemlist .items .item的div里面
)
html = self.driver.page_source #获取网页的源代码
soup = BeautifulSoup(html,'html.parser')
items = soup.find('div',class_ = 'm-itemlist').find_all('div',class_ = 'item') #定位到单独的商品上
for item in items: #这个循环用来获取整个页面每一个商品的五个信息
product = {
'image':item.find('a').find('img')['src'],
'price':item.find('div',class_ = ['price','g_price g_price-highlight']).find('strong').text,
'num':item.find('div',class_ = 'deal-cnt').text[:-3],
'name':item.find('div',class_ = 'row row-2 title').find('a').text.strip(),
'location':item.find('div',class_ = 'location').text
}
print(product) #循环打印每一个商品信息
最后一步:翻页
我们总不能只爬一页吧,哈哈哈,那样会感觉有点菜菜的。
在页面的最下面有页码,然后还有一个框,里面可以填你想跳转的页数,然后点旁边的按钮即可。
那么我们首先要做的就是定位到这个框里面,然后把里面的数字页码清空,我们自己自动输入一个进去,
然后再定位到旁边的按钮,点击确定,然后就可以跳转到下一页了。所以就很简单的啦。
方法长这样:
def next_page(self,page):
print(u'当前是第{}页'.format(page))
#检查input标签是否出现,出现的话进行后面的代码,这个标签就是我们想要定位的那个可以输入页码的框框
input = self.wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > input'))
)
#用来清空页码
input.clear()
#element_to_be_clickable用来检查按钮是否可以被点击
submit = self.wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit'))
)
input.send_keys(page) #输入页码值
submit.click() #点击确定,跳转到下一页
#text_to_be_present_in_element用来确定某个文本是否包含在这个标签里面,这里是为了确保翻到了第二页,而且这里如果检查到了,也说明整个网页加载完成了,因为这个页数在网页的最下面。
self.wait.until(
EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > ul > li.item.active > span'),str(page)) #参数里面的str(page)是当前页的页码数,我们为了确定当前页面是否是我们跳转的页面才这样写
)
tb.get_response() #确定了跳转到下一页并加载完成后,进行下一次的信息爬取
那么方法的介绍就到这里,下面贴上源代码,写的有点丑,希望各位多多见谅,这是我的第二个练手项目。以后还会不断上传新的练手项目。
源代码如下:
# -*- coding:utf-8 -*- from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException #超时的异常 from bs4 import BeautifulSoup class TB: def __init__(self): self.driver = webdriver.Chrome() self.wait = WebDriverWait(self.driver,10) def search(self,shop = None): print('开始搜索了') self.driver.get('https://www.taobao.com') try: #判断输入框是否加载完成 input = self.wait.until( #返回的对象应该是所要寻找的目标元素 EC.presence_of_element_located((By.CSS_SELECTOR,'#q')) #presence_of_element_located这个函数接收的参数是元组,表示检查某个元素是否在dom树里面,如果存在就返回这个元素,否则返回布尔值。 ) input.send_keys(u'{}'.format(shop)) #format格式化,将page传入{}里面 #判断按钮是否加载完成 submit = self.wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR,'#J_TSearchForm > div.search-button > button')) #判断某个按钮是否可以点击,可以就返回这个按钮 ) submit.click() #点击按钮 except TimeoutException: raise TimeoutException def get_response(self): #判断当前的商品加载出来没有 self.wait.until( EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#mainsrp-itemlist .items .item')) ) html = self.driver.page_source soup = BeautifulSoup(html,'html.parser') items = soup.find('div',class_ = 'm-itemlist').find_all('div',class_ = 'item') for item in items: product = { 'image':item.find('a').find('img')['src'], 'price':item.find('div',class_ = ['price','g_price g_price-highlight']).find('strong').text, 'num':item.find('div',class_ = 'deal-cnt').text[:-3], 'name':item.find('div',class_ = 'row row-2 title').find('a').text.strip(), 'location':item.find('div',class_ = 'location').text } print(product) def next_page(self,page): print(u'当前是第{}页'.format(page)) #检查input标签是否出现,出现的话进行后面的代码 input = self.wait.until( EC.presence_of_element_located((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > input')) ) #用来清空页码 input.clear() #element_to_be_clickable用来检查按钮是否可以被点击 submit = self.wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit')) ) input.send_keys(page) submit.click() #text_to_be_present_in_element用来确定某个文本是否包含在这个标签里面,这里是为了确保翻到了第二页,而且这里如果检查到了,也说明整个网页加载完成了,因为这个页数在网页的最下面。 self.wait.until( EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > ul > li.item.active > span'),str(page)) ) tb.get_response() if __name__ == '__main__': tb = TB() shop = input('请输入要搜索的商品名字:\n') tb.search(shop) tb.get_response() for i in range(2,4): tb.next_page(i)