在解决了淘宝登录问题以后就开始进行淘宝商品的爬取,住要是利用Selenium抓取淘宝商品并用pyquery解析得到商品的图片、名称、价格、购买人数、店铺名称和店铺所在地信息,并将其保存到Excel中具体实现可以参考GitHub:爬取淘宝商品列表。
登录淘宝
关于自动登录淘宝的问题上篇已经介绍过淘宝爬虫之自动登录,
跳转分类搜索页面
在登录成功以后,我们直接跳转到需要分类的搜索页面,抓取的入口就是淘宝的搜索页面,例如搜索面膜:https://s.taobao.com/search?q=面膜,这个链接可以通过直接构造参数访问,显示的就是第一页的搜索结果,
在页面下方,有一个分页导航,其中既包括前5页的链接,也包括下一页的链接,同时还有一个输入任意页码跳转的入口,这里商品的搜索结果一般最大都为100页,要获取每一页的内容,只需要将页码从1到100顺序遍历即可,页码数是确定的。所以,直接在页面跳转文本框中输入要跳转的页码,然后点击“确定”按钮即可跳转到页码对应的页面。
当然也可以通过通过获取'下一页'标签来获取下页的数据,我看到有些人是通过点击下一页来获取列表的数据,例如python采集淘宝教程!但是解析处理起来会有些麻烦,而且遇到错误解析中断的情况下不好做后续处理,如果感兴趣的话可以参考上面的教程
解析商品列表
根据构造的URL:https://s.taobao.com/search?q=面膜。来获取商品列表,参数q
就是要搜索的关键字。只要改变这个参数,即可获取不同商品的列表。这里我们将商品的关键字定义成一个变量,然后构造URL。
然后,就需要用Selenium进行抓取了:
def index_page(self, page):
"""
根据页码获取商品列表
:param page: 页码
"""
print('正在爬取第', page, '页')
self.page = page
try:
if page == 1:
url = 'https://s.taobao.com/search?q=' + quote(KEYWORD)
self.browser.get(url)
if page > 1:
input = self.wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager div.form > input')))
submit = self.wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager div.form > span.btn.J_Submit')))
input.clear()
input.send_keys(page)
submit.click()
self.wait.until(
EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'), str(page)))
self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.m-itemlist .items .item')))
self.get_products()
except NoSuchElementException:
self.browser.get_screenshot_as_file('error.png')
self.index_page(page)
KEYWORD :搜索商品的关键字
在登录成功以后,然后指定一个关键词,如面膜,然后跳转到相应的搜索页面,然后调用index_page()方法,根据page获取相关的商品列表页。
在这之前我们先获取输入框和确定按钮,首先先清空了输入框,此时调用clear()方法即可。随后,调用send_keys()方法将页码填充到输入框中,然后点击“确定”按钮,然后等待页面加载。
等待商品列表加载
等待加载时,我们使用了WebDriverWait对象,它可以指定等待条件,等待页面加载完成,找到某个条件发生后再继续执行后续代码,如果超过设置时间检测不到则抛出异常
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
driver:WebDriver 的驱动程序(Ie, Firefox, Chrome 或远程)
timeout:最长超时时间,默认以秒为单位
poll_frequency:休眠时间的间隔(步长)时间,默认为 0.5 秒
ignored_exceptions:超时后的异常信息,默认情况下抛 NoSuchElementException 异常
如1:element = WebDriverWait(driver, 10).until(lambda x : x.find_element_by_id("id"))
element.send_keys("selenium")
如2:element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id(“Id”))
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).until_not(lambda x: x.find_element_by_id(“someId”).is_displayed())
WebDriverWai()一般由 unit()或 until_not()方法配合使用:
until(method, message=’’)
调用该方法提供的驱动程序作为一个参数,直到返回值不为 False。
until_not(method, message=’’)
调用该方法提供的驱动程序作为一个参数,直到返回值为 False。
self.wait = WebDriverWait(self.browser, 10, poll_frequency=1)
这里指定为最长10秒。如果在这个时间内成功匹配了等待条件,也就是说页面元素成功加载出来了,就立即返回相应结果并继续向下执行,否则到了最大等待时间还没有加载出来时,就直接抛出超时异常。
比如,我们最终要等待商品信息加载出来,就指定了presence_of_element_located这个条件,然后传入了.m-itemlist .items .item这个选择器,而这个选择器对应的页面内容就是每个商品的信息块,可以到网页里面查看一下。如果加载成功,就会执行后续的get_products()方法,提取商品信息。
解析商品列表数据
下面是使用get_products()方法来解析商品列表的,这里我们直接获取页面源代码,然后用pyquery进行解析,首先,调用page_source属性获取页码的源代码,然后构造了PyQuery解析对象,接着提取了商品列表,此时使用的CSS选择器是#mainsrp-itemlist .items .item,它会匹配整个页面的每个商品。它的匹配结果是多个,所以这里我们又对它进行了一次遍历,用for循环将每个结果分别进行解析,每次循环把它赋值为item变量,每个item变量都是一个PyQuery对象,然后再调用它的find()方法,传入CSS选择器,就可以获取单个商品的特定内容了。因为我现在要把数据写入到Excel中所以要构造一个二维数据,当然也可以通过构造对象存到数据库中,具体实现如下:
def get_products(self):
"""
提取商品数据
"""
print('解析网页数据')
html = self.browser.page_source
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
products = []
for item in items:
product = list()
product.append(item.find('.pic .img').attr('data-src'))
product.append(item.find('.price').text())
product.append(item.find('.deal-cnt').text())
product.append(item.find('.title').text())
product.append(item.find('.shop').text())
product.append(item.find('.location').text())
# product = {
# 'image': item.find('.pic .img').attr('data-src'),
# 'price': item.find('.price').text(),
# 'deal': item.find('.deal-cnt').text(),
# 'title': item.find('.title').text(),
# 'shop': item.find('.shop').text(),
# 'location': item.find('.location').text()
# }
products.append(product)
self.__write_product(products)
保存数据并跳转下一页面
数据的保持主要是通过写入Excel进行的,写入Excel的用用法之前介绍过
def __write_product(self, products):
titles = ['图片', '价格', '销量', '标题', '店铺', '归属地']
if self.page == 1:
for num in range(len(titles)):
self.sheet1.write(0, num, titles[num])
for row in range(len(products)):
for col in range(6):
self.sheet1.write(row + 1 + (len(self.productlist) - len(products)), col, products[row][col])
self.workbook.save('Workbook.xls')
print('创建execel完成!')
页面数据的获取是通过循环来进行获取的,可以设置一个最大页面
def __search(self):
"""
遍历每一页
"""
for i in range(1, MAX_PAGE + 1):
self.index_page(i)
self.browser.close()
我调试的过程中,我一般设置最大页面是10页,但是偶尔还是会出现等待加载超时的情况,暂时还没做处理,另外淘宝对于淘气值较低的账号好像审核较高些,我之前用一个淘气值400的账号登录,几次之后就开始出现滑块然后不能自动登录,但由于我的另一个淘宝的淘气值是在一千以上,所以即使有滑块也能通过自动登录。
淘宝商品列表的爬取是在上一篇的基础上做了进一步扩展,关于登录可以参考:淘宝爬虫之自动登录
本篇文章具体实现可以参考GitHub:爬取淘宝商品列表
这篇文章主要参考崔庆才的: [Python3网络爬虫开发实战] 7.4-使用Selenium爬取淘宝商品
,博客里面也有很多文章值得学习。很多地方可能写的不够完善,欢迎探讨指正。