爬取淘宝美食页面

思路

  • 模拟在淘宝的搜索框填写关键词,然后搜索
  • 模拟数据加载完毕后,点击下一页操作
  • 数据加载结束以后利用PyQuary进行数据解析提取
  • 存储到mongoDB
  • 代码细节优化

工具安装

  • 安装 selenium
    brew install selenium-server-standalone
  • 安装PyQuery
    sudo easy_install pyquery
  • 安装phantomjs
    brew install phantomjs

利用 selenium模拟淘宝操作

使用selenium的大致思路根据CSS选择器或者id之类的定位到具体的控件,然后给控件实现赋值或者点击等操作。

selenium的简单配置

  • 导入框架
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
  • 加载浏览器驱动,本例中使用谷歌浏览器,使用前请确认已经安装
    chromedriver,关于配置可以自行Google或者访问我的博客
    支持的浏览器
选择元素css
# 加载驱动
browser = webdriver.Chrome()

此时代码运行可以呼起一个空置的谷歌浏览器

  • 设置等待超时时间:在规定时间内未能加载相应控件将报错
wait = WebDriverWait(browser, 10)
  • 通用写法
wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))
        )
  • 代码分析

    • EC 为from selenium.webdriver.support import expected_conditions as EC
    • EC后边的是选择条件,即什么时候可以选择控件,例中条件为控件完全展示,其他选择条件请看下面 EC选择条件
    • By 为from selenium.webdriver.common.by import By
    • By后边的是根据什么元素选择控件,可以使id 或者css等等,后边的参数为具体的元素值
  • EC选择条件

title_is
title_contains
presence_of_element_located
visibility_of_element_located
visibility_of
presence_of_all_elements_located
text_to_be_present_in_element
text_to_be_present_in_element_value
frame_to_be_available_and_switch_to_it
invisibility_of_element_located
element_to_be_clickable
staleness_of
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
alert_is_present
  • By参数类型
    ID = "id"
    XPATH = "xpath"
    LINK_TEXT = "link text"
    PARTIAL_LINK_TEXT = "partial link text"
    NAME = "name"
    TAG_NAME = "tag name"
    CLASS_NAME = "class name"
    CSS_SELECTOR = "css selector"

模拟关键字填写及搜索

  • 输入框的EC条件为presence_of_element_located,然后利用其css选择器,并复制其id
  • 确定按钮EC条件为element_to_be_clickable同样选择其css值
  • 输入框内通过send_keys传入搜索词
  • 确定按钮调用click()方法
  • 其他的方法参见文档
  • 坑:send_keys输入关键字的时候,在Python2.7的环境中,如果直接用字符串会报错
    UnicodeDecodeError: 'utf8' codec can't decode byte 0xe7in position 0: unexpected end of data
    可以通过解码进行修复"美食".decode(encoding="utf-8")
browser.get("https://s.taobao.com")
    # selenium处理页面等待的方法
    # 设置一下需要监听的元素,可以通过id或者能唯一确定元素的属性
    # EC是选择条件点后边的是条件,我把条件记录在简书里
    # 我们通过页面元素,查找到输入框,我们利用css样式去确定,并利用css选择器去获取
        input = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))
        )

        # 然后监听按钮,条件是以可以点击判断其加载完成
        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#J_SearchForm > div > div.search-button > button"))
        )

        # 调用selenium的API来给搜索框输入内容,然后按钮追加点击方法
        # send_keys添加参数
        input.send_keys(KEYWORD)
        # 添加点击方法
        submit.click()

获取宝贝页面的宝贝总页数

  • 监听翻页控件加载完,以显示共xx页显示完全为依据
  • EC的条件也就是presence_of_element_located,同样利用其css选
    择器
  • 将返回页数作为返回值返回
 total = wait.until(
       EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.total"))
  )
return total.text

实现翻页

翻页功能有种实现方式

  • 点击下一页,实现翻页,但是如果发生错误不易差别是具体页数

  • 输入页码,点击确定,可以清楚的知道具体跳转了那一页,翻页后确定当前面是否加载完,主要看页码当时是否为高亮状态


  • 定义一个以页码作为参数的函数

  • 获取页码户输入框架,获取确定按钮,输入框填入参数,然后点击确定实现翻页,与搜索功能相同

  • 确定当前页码的高亮状态来

def get_next_page(page_number):
    print(u"正在翻页")
    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()

        # 翻页后确定当前面是否加载完,主要看页码当时是否为高亮状态
        text = 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_product()
    except TimeoutException:
        print("get_next_page超时")
        get_next_page(page_number)

PyQuery实现页面解析

对于PyQuery(以下简称pq)的用法目前完全懵逼,完全是跟着视频敲的,只知道类似于jQuery,根据id或者css样式去获取查找元素,页面结果见下图,通过idmainsrp-itemlist的,然后css样式为items获取商品列表,最后通过css样式为items,然后每个商品的信息

网页结构图
  • 没啥说的直接上代码
'''
3.解析页面,获取美食信息
'''
def get_product():
    print("正在获取产品")
    # 页面记载结束:主要是看商品信息的大节点是不是加载完了
    wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-itemlist .items .item"))
    )
    # 获取页面内容
    html = browser.page_source
    # 通过PyQuery解析页面
    doc = pq(html)
    # 根据节点获取美食的集合
    items = doc("#mainsrp-itemlist .items .item").items()
    # 遍历 获取各值
    for item in items:
        product = {
            # 获取img标签下的src属性
            "image": item.find(".pic .img").attr("src"),
            "price": item.find(".price").text(),
            "deal": item.find(".deal-cnt").text()[:-3],
            "title": item.find(".title").text(),
            "shop": item.find(".shop").text(),
            "location": item.find(".location").text()
        }
  • 在第一次加载页面方法时,也就是第一页的时候调用此方法,获取第一页的数据
  • 在翻页的时候也要调用此方法

存储到mongoDB

与第一篇爬取头条数据一样,需要单独创建配置文件,然后创建俩呢及,创建数据库,存储数据,有一点着重提示的是,在代码运行存储数据的时候,一定要记得开启mongoDB的服务,不然会报一些莫名其妙的错误

  • 配置文件代码
MONGO_URL = "localhost"
MONGO_DB = "Taobao"
MONGO_TAB = "TbCate"
  • 创建数据库连接
# 创建数据库链接
client = MongoClient(MONGO_URL)
# 创建数据库
db = client[MONGO_DB]
  • 存储数据
'''
4.存储数据
'''
def save_to_mongo(result):
    try:
        if db[MONGO_TAB].insert(result):
            print("正在存储到mongDB")
    except Exception:
        print("存储失败",result)

代码整体串接

def main():
    try:
        # 获取总页数
        totoal = search()
        # 获取数字,过滤汉字
        pattern = re.compile(r"(\d+)")
        match = re.search(pattern, totoal)
        # 遍历获取所有的页面
        for i in range(2,int(match.group(1)) + 1):
            get_next_page(i)
        # 数据获取结束以后关闭浏览器
    except Exception:
        print("出错了")
   # 用完后,必须关闭浏览器
    finally:
        browser.close()

引入phantomJS

我感觉如果遇到一个具体类似淘宝宝贝数据爬取的需求的话,可能的大致思路是先通过浏览器去模拟数据,成功以后,引入phantomJS去静默爬取数据

  • 配置phantomJS
# 将Google浏览器换成PhantomJS
browser = webdriver.PhantomJS()
# 修改弹框大小
browser.set_window_size(1400,800)
  • PhantomJS的一些高级配置,详见官网
    • 在配置文件中简单进行配置
# phantomJS的高级用配置:不加载图片,加缓存
SEARVICE_ARGS = ["--load-images=false","--disk-cache=true"]
  • 代码中引入
browser = webdriver.PhantomJS(service_args=SEARVICE_ARGS)

一些注意点

  • selenium 等待控件加载的时候,容易发生超时问题,所以要加异常处理,一般超时后都是在调用一遍方法
  • 引入 PhantomJS以后,browser.close()会报错,所以也要加异常处理,在finally后边关闭
  • 存储到mongoDB的时候一定要先开启mong服务
  • 本博客对PyQueryPhantomJS没有进行详细的讲解,因为本人基础薄弱,但是给了一些博客链接,待到本人学习以后会将博客进行完善,另外本博客在GitHub的源码README中同步更新了
  • 代码地址
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容