四、selenium+beautifulsoup4获取淘宝商品评论及图片

概述

  • 使用firefox浏览器
  • 使用selenium时,只能使用扫码登录,不能使用用户名密码登录
  • 使用用户名密码登录时会提示"==哎呀,出错了,点击刷新再来一次(error:9PiETg)=="
  • 扫码登录后可以将cookie保存,下一次可以使用cookie登录,避免每次运行都要扫码
  • 保存的cookie会有失效时间
  • 支持淘宝链接,天猫链接和短链接
  • 爬取时还有获取页面元素不稳定的问题,暂时没找到好办法,只能多试几次
  • 商品评论的页数只能到99页,多于99页会提示错误
  • 翻页太快会导致出现验证,并且验证时会提示"==哎呀,出错了,点击刷新再来一次(error:9PiETg)=="

效果

评论内容
评论图片

实现

源码文件

源码
文件 介绍
main.py 爬虫入口,创建保存目录,扫码登录或cookie登录,开启爬虫
core.py 爬虫判断,根据url创建TMall或者Taobao爬虫
spider文件夹 taobaoSpider.py和tmallSpider.py 实现了淘宝商品评论爬取和天猫商品评论爬取
browser.py WebDriver FireFox抽象
util.py 工具类
settings.py 配置如扫码登录还是cookie,图片存储目录,url等

main.py

# coding=utf-8
import json
import os

import settings
import util
from core import Crawler
from browser import FirefoxBrowser

#创建图片目录
util.mkStorePath(settings.STORE_PATH)

firefox = FirefoxBrowser()
#扫码登录并保存cookie
if settings.QRCODE == True:
    cookies = firefox.get_cookies(settings.LOGIN_URL)
    jsonCookies = json.dumps(cookies)
    with open("cookies_tao.json", "w") as fp:
        fp.write(jsonCookies)
        fp.close()
    print("cookie file done")
#否则使用保存的cookie登录
else:
    firefox.get(settings.LOGIN_URL)
    if os.path.exists('cookies_tao.json'):
        with open("cookies_tao.json","r",encoding="utf8") as fp:
            cookies = json.loads(fp.read())
            firefox.set_cookies(cookies)
            fp.close()

#爬取商品评论
failedList = []
#第一遍有失败的
for url in settings.URLS:
    isSuccess = Crawler(url,firefox).start()
    if isSuccess == False:
        failedList.append(url)
#失败的重试一次
for url in failedList:
    Crawler(url,firefox).start()

firefox.close()

core.py

# coding=utf-8
import os
from time import sleep

from spider.tmallSpider import TmallSpider
from spider.taobaoSpider import TaobaoSpider
import settings

class Crawler(object):

    def __init__(self, target_url,firefoxBrowser):
        #TODO 验证url可用性
        self._firefox = firefoxBrowser
        if(target_url.find('detail.tmall.com') != -1):
            self._type = 1
        elif(target_url.find('item.taobao.com') != -1):
            self._type = 2
        elif(target_url.find('m.tb.cn') != -1):
            self._type = 0
        self._firefox.get(target_url)
        if self._type == 0:
            self._firefox._wait_url(target_url,300)
        self._url = self._firefox.driver().current_url

    def start(self):
        """
        :return: True False
        """
        #判断爬虫类型
        if(self._url.find('detail.tmall.com') != -1):
            return TmallSpider(self._firefox).start()
        elif(self._url.find('item.taobao.com') != -1):
            return TaobaoSpider(self._firefox).start()

spider/tmallSpider.py

# coding=utf-8
import time
from bs4 import BeautifulSoup
from urllib.request import urlretrieve

import settings
import util
from util import ElementFilter

class TmallSpider(object):

    def __init__(self,firefoxBrowser):
        self._firefox = firefoxBrowser
        self._surl = self._firefox.driver().current_url
        self._sid = util.getIdAndMkdir(self._surl,settings.STORE_PATH)
        self._item = {}
        self._rate = []

    def start(self):
        """
        :return: True-爬取完成 False-爬取失败
        """
        #判断爬虫类型
        print('start tmallSpider ' + str(self._sid))
        #获取item的标题
        print('get Title')
        self._item['title'] = self._firefox.get_element(ElementFilter.tm_dict['Title']).text
        #找到包含评论页面的view
        print('get JTabBarBox')
        element = self._firefox.get_element(ElementFilter.tm_dict['JTabBarBox'])
        self._firefox.driver().execute_script("arguments[0].scrollIntoView()",element)
        #找到包含radio的容器
        print('get JTabbar')
        jtabbar = self._firefox.get_element_without_wait(ElementFilter.tm_dict['JTabbar'])
        if jtabbar is None:
            print('JTabbar not found')
            return False
        jtabbar.click()
        time.sleep(5)
        #找到radio并点击包含图片的评论
        print('get JReviews')
        jreviews = self._firefox.get_element_without_wait(ElementFilter.tm_dict['JReviews'])
        if jreviews is None:
            print('JReviews not found')
            return False
        jreviews.click()
        time.sleep(5)
        #找到图片评论,最多99页
        for num in range(1,99):
            temp = self.parse(self._firefox.driver().page_source)
            self._rate.append(temp)
            print('page'+str(num))
            num = num + 1
            isLast = self._firefox.get_next_page_tmall('下一页>>')
            if isLast == False:
                break
            time.sleep(5)
        self._item['rates'] = self._rate
        return True

    def parse(self,html):
        bs4 = BeautifulSoup(html,"html.parser")
        div_rate = bs4.find("div",class_="rate-grid")
        items = []
        #选择每一行
        trs = div_rate.select('tr')
        for tr in trs:
            item = {}
            
            #td class="col-author" 作者
            td3 = tr.select_one('td.col-author')
            contents = td3.select_one('div.rate-user-info').contents
            item['author'] = contents[0].strip()+ "***" + contents[2].strip()
            item['rauthor'] = contents[0].strip() + contents[2].strip()

            #td class="tm-col-master"  评论内容和图片地址
            td1 = tr.select_one('td.tm-col-master')
            #追评 tm-rate-premiere 否则 tm-rate-content
            premiere = td1.select_one('div.tm-rate-premiere')
            if premiere is not None:
                print('premiere')
                #tm-rate-premiere
                #初始评论内容
                fulltxt = premiere.select_one('div.tm-rate-fulltxt').contents
                if len(fulltxt) > 1:
                    item['tm-rate-fulltxt'] = fulltxt[1].strip()
                else:
                    item['tm-rate-fulltxt'] = fulltxt[0].strip()
                item['tm-rate-fulltxt'] = fulltxt
                #评论时间
                date = premiere.select_one('div.tm-rate-date').contents[0].strip()
                item['tm-rate-date'] = date
                #评论图片url
                lis = premiere.select('li')
                datasrc=[]
                for li in lis:
                    srcLi = li.attrs['data-src']
                    if srcLi.endswith(".png"):
                        continue
                    imgUrl = self.parseImg(srcLi,item['rauthor'])
                    datasrc.append(imgUrl)
                #追评内容
                append = td1.select_one('div.tm-rate-append')
                fulltxt = append.select_one('div.tm-rate-fulltxt').contents
                if len(fulltxt) > 1:
                    item['tm-rate-fulltxt'] = fulltxt[1].strip()
                else:
                    item['tm-rate-fulltxt'] = fulltxt[0].strip()
                item['append-rate-fulltxt'] = fulltxt
                alis = append.select('li')
                for li in alis:
                    srcLi = li.attrs['data-src']
                    if srcLi.endswith(".png"):
                        continue
                    imgUrl = self.parseImg(srcLi,item['rauthor'])
                    datasrc.append(imgUrl)
                item['tm-m-photos'] = datasrc
            else:
                #tm-rate-content
                content = td1.select_one('div.tm-rate-content')
                #评论内容
                fulltxt = content.select_one('div.tm-rate-fulltxt').contents
                if len(fulltxt) > 1:
                    item['tm-rate-fulltxt'] = fulltxt[1].strip()
                else:
                    item['tm-rate-fulltxt'] = fulltxt[0].strip()
                        #评论图片url
                lis = content.select('li')
                datasrc=[]
                for li in lis:
                    srcLi = li.attrs['data-src']
                    if srcLi.endswith(".png"):
                        continue
                    imgUrl = self.parseImg(srcLi,item['rauthor'])
                    datasrc.append(imgUrl)
                item['tm-m-photos'] = datasrc
                #评论时间
                date = td1.select_one('div.tm-rate-date').contents[0].strip()
                item['tm-rate-date'] = date
            #td class="col-meta" 颜色和鞋码
            td2 = tr.select_one('td.col-meta div.rate-sku')
            ps = td2.select('p')
            item['color'] = ps[0]['title']
            item['size'] = ps[1]['title']
            
            items.append(item)
        return items

    def parseImg(self,picUrl,author):
        picTemp = picUrl.rpartition('/')[2]
        picDes = settings.STORE_PATH + '/' + self._sid + "/" + author + '_' + picTemp[:len(picTemp)-12]
        picAll = "http:" + picUrl[:len(picUrl)-12]
        urlretrieve(picAll,picDes)
        return picAll

参考

selenium文档
Beautiful Soup 4.4.0 文档
CSS 选择器参考手册
selenium爬取淘宝评论信息
python +Selenium 爬取淘宝商品评论

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352