-
-
目标网站分析
打开淘宝网站,关键字搜索美食,根据分析ajax请求的方法查看请求url信息,发现比较多而且杂乱而且preview中不包含商品信息,直接请求或分析ajax很繁琐,因此不采用分析ajax抓取。
这里改用selenium模拟浏览器,(selenium可以驱动浏览器实现点击、输入、下拉等功能),这样我们只关心操作,不用关心后台发生了怎样的请求。
-
流程框架
- 搜索关键字: 利用Selenium驱动浏览器搜索关键字,得到查询后的商品列表;
- 分析页码并翻页:得到商品页码数,模拟翻页,得到后续页面的商品的商品列表;
- 分析提取商品内容:利用PyQuery分析源码,解析得到商品列表;
- 存储到MongoDB:将商品列表信息存储到数据库MongoDB.
-
爬虫实战
from selenium import webdriver
browser = webdriver.Chrome() # 在此处运行下 会出现由自动化测试软件驱动的Chrome浏览器
如果发生错误,可能你缺少ChromeDriver,你可以在淘宝镜像源http://npm.taobao.org/mirrors/chromedriver/ 下载对应版本并配置环境变量。 配置好以后,可在命令行中查看:
出现上面的信息则说明 配置成功。
后面获取输入页码框的步骤同上。
下载Phantomjs
官网中http://phantomjs.org/download.html选择对应的版本,并加入环境变量。
这里建立软链接:ln -s /home/yufeng/software/phantomjs-2.1.1/bin/phantomjs /usr/bin
如果运行时出现如下错误:
selenium.common.exceptions.WebDriverException: Message: 'phantomjs' executable needs to be in PATH.
说明你的phantomjs没有加入到环境变量。
抓取美食工程结构图:
MONGODB:
完整代码:
config.py
# -*- coding: utf-8 -*-
# @Time : 18-8-20 下午4:58
# @Author : yufeng
# @Blog :https://blog.youkuaiyun.com/feng_zhiyu
MONGO_URL = 'localhost'
MONGO_DB = 'taobao'
MONGO_TABLE = 'product'
# http://phantomjs.org/api/command-line.html
# 默认加载图片,设置为不加载图片 节省时间; 默认为不开始缓存,这里开启缓存
SERVICE_ARGS = ['--load-images=false', '--disk-cache=true']
KEYWORD = '美食'
# -*- coding: utf-8 -*-
# @Time : 18-8-20 下午3:30
# @Author : yufeng
# @Blog :https://blog.youkuaiyun.com/feng_zhiyu
import re
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq
from config import *
import pymongo
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGO_DB]
# browser = webdriver.Chrome() # 在此处运行下 会出现由自动化测试软件驱动的Chrome浏览器
browser = webdriver.PhantomJS(service_args=SERVICE_ARGS)
wait = WebDriverWait(browser, 10)
browser.set_window_size(1400, 900) #设置phantomjs窗口大小
'''
使用selenium模拟浏览器输入与点击
'''
def search():
print('正在搜索')
try:
url = "https://www.taobao.com/"
browser.get(url)
# 参考:https://selenium-python.readthedocs.io/waits.html#explicit-waits
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#q")) # 搜索输入框选择器
)
# 搜索 按钮(可点击的)
submit = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "#J_TSearchForm > div.search-button > button")))
# 模拟操作 参考:https://selenium-python.readthedocs.io/api.html
input.send_keys(KEYWORD)
submit.click()
# 等待一下, 同样通过CSS选择器找到页数
total = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.total')))
get_products() # 所有页面加载完毕后获取宝贝信息
return total.text
except TimeoutException:
return search()
'''
获取下一页
'''
def next_page(page_number):
print("正在翻页", page_number)
try:
# 页码输入框
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input"))
)
# 确定 按钮(可点击的)
submit = wait.until(
EC.element_to_be_clickable(
(By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit")))
input.clear()
input.send_keys(page_number) # 输入页码数
submit.click() # 执行翻页操作
# 接下来判断是否已经翻页 传入当前高亮的页码,和当前页数
wait.until(EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number)))
get_products()
except TimeoutException:
next_page(page_number)
'''
获取宝贝信息
'''
def get_products():
# 判断宝贝是否加载成功
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
html = browser.page_source
# 通过PyQuery解析html代码
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
product = {
# item.find()获取内部元素
'image': item.find('.pic .img').attr('src'),
'price': item.find('.price').text(),
'deal': item.find('.deal-cnt').text()[:-3], # 成交量 666人付款, 去掉最后的三个字
'title': item.find('.title').text(),
'shop': item.find('.shop').text(),
'location': item.find('location').text()
}
print(product)
save_to_mongo(product)
'''
保存到MongoDB
'''
def save_to_mongo(result):
try:
if db[MONGO_TABLE].insert(result):
print("存储到MONGODB成功", result)
except Exception:
print("存储到MONGODB失败", result)
def main():
try:
total = search()
# 使用正则表达式提取 数字100
total = int(re.compile('(\d+)').search(total).group(1))
for i in range(2, total + 1):
next_page(i)
except Exception:
print("出错啦")
finally:
browser.close()
if __name__ == '__main__':
main()