利用selenium抓取淘宝商品列表及评论并保存到数据库
开始写爬虫代码前,我们需要先思考下你需要得到哪些信息
在这里,我需要得到的是淘宝指定商品的信息,包括价格、店铺、销量、标题、卖家、地址,还有就是各商品的所有用户评价信息,抓取到这些信息后可以方便我们后续的数据分析
最后面有我的完整代码
首先打开淘宝,审查元素
然后检查网页源代码,看网页源代码里是否含有商品的信息,在这里ctrl+f搜索某商品的价格,这里发现商品价格信息之类的都在一个script标签里,说明淘宝的商品列表都是通过js渲染出来的
那么我们可以用正则提取网页的商品信息,也可以用selenium,这里为了方便,我就用selenium了
下面是抓取商品信息的代码,如果不懂的话这里有视频详细解析,代码也源自这位博主,感谢他,我只是稍作修改
#导入需要的库 import re from pyquery import PyQuery as pq #解析库 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 browser = webdriver.Chrome() #等待变量 wait = WebDriverWait(browser,10) #模拟搜索 def search(): try: browser.get('https://www.taobao.com/')#打开淘宝首页 tb_input = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, '#q')) )#等待输入框加载完成 search_btn = wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button')) )#等待搜索按钮加载完成 tb_input.send_keys('口红')#输入框中传入你需要搜索的商品 search_btn.click()#点击搜索 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 get_products(): wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')) )#等待商品信息加载完成,商品信息的CSS选择器分析HTML源码得到 html = browser.page_source#得到页面HTML源码 doc = pq(html)#创建PyQuery对象 items = doc('#mainsrp-itemlist .items .item').items()#获取当前页所有商品信息的html源码 for item in items: #这里为了后面获取商品的评论信息,需要知道商品id以及店铺id product = { # 'image':item.find('.pic .img').attr('src'), 'itemid':item.find('.shop .shopname').attr('data-nid'), 'sellerid':item.find('.shop .shopname').attr('data-userid'), 'url':item.find('.title .J_ClickStat').attr('href'), 'price':item.find('.price').text(), 'deal':item.find('.deal-cnt').text()[:-3], 'title':item.find('.title').text(), 'seller':item.find('.shop').text(), 'location':item.find('.location').text() } print(product) #翻页函数 def next_page(page_number): try: page_input = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input')) )#等待翻页输入框加载完成 confirm_btn = wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit')) )#等待确认按钮加载完成 page_input.clear()#清空翻页输入框 page_input.send_keys(page_number)#传入页数 confirm_btn.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)) )#确认已翻到page_number页 get_products() except TimeoutException: next_page(page_number)#若发生异常,重新调用自己 def main(): total = search()#获取商品页数,字符串类型 total = int(re.compile('(\d+)').search(total).group(1))#利用正则表达式提取数字,并强制转换为int类型 for i in range(2, total+1): next_page(i) browser.close() if __name__ == '__main__': main()
接下来我们就是将数据保存到数据库了
首先保存到mongodb的函数代码如下
import pymongo #创建数据库以及数据表 client = pymongo.MongoClient('localhost',27017) dataname = client['tb_kouhon'] table = dataname['goods_info'] def save_to_mongoDB(product): try: if table.insert(product): print('存储到MongoDB成功',product) except Exception: print('存储到MongoDB失败',product)
将该函数插入到get_products()中
运行一下,淘宝每页有48个商品,总共100页,除掉重复的数据,发现和我们得到4000多条数据基本一致
接下来在练习一下保存数据到mysql
首先打开mysql终端创建数据库及数据表
#创建数据库 mysql> create database tb; Query OK, 1 row affected (0.00 sec) 创建数据表 mysql> use tb; Database changed mysql> create table tb_inf( -> id smallint unsigned auto_increment primary key, -> itemid varchar(30), -> sellerid varchar(30), -> url varchar(200), -> price varchar(20), -> deal varchar(20), -> title varchar(200), -> seller varchar(50), -> location varchar(50) -> ); Query OK, 0 rows affected (0.22 sec)
然后创建存储到mysql的函数,这里要特别注意一点,利用pymysql插入数据到mysql是字符字段要有双引号括起来,不然会报错,这个非常重要,血泪般的教训==
def save_to_mysql(product): sql = '''INSERT INTO tb_info(itemid,sellerid,url,price,deal,title,seller,location) VALUES (%s,%s,"%s","%s",%s,"%s","%s","%s")''' try: cursor.execute(sql % (product['itemid'],product['sellerid'],product['url'],product['price'],product['deal'],product['title'],product['seller'],product['location'])) conn.commit() except: conn.rollback()
ok,接下来运行下,爬几分钟就ok了,和上次爬的相比少了几十条数据,不过无关紧要了
接下来我们就是开始抓取淘宝各商品的评论了
这里因为淘宝商品有反爬策略,频繁爬取需要登录,还要输入验证码
所以在这里只演示爬取天猫商品的评论
首先我们随便打开一个天猫商品的全部评论,打开network,翻几页评论
点开response,可以发现里面全是json数据,这个list_detail_rate.htm?里面就是就是我们需要的数据
接下来我们看一下他的request url
这里我试了下,url可以简写成
https://rate.tmall.com/list_detail_rate.htm?itemId=546724870335&sellerId=3170729146¤tPage=4
访问下试试,如我们所料,评论都在这
在看下简化后url的构成,可以分成三部分itemId,sellerId,currentPage分别表示商品id,店铺id,评论页数
接下来就简单了
首先我们把上面爬取到的商品信息读取出来
import pymongo client = pymongo.MongoClient('localhost',27017) dataname = client['tb_kouhon'] table = dataname['goods_info'] allgoods = [] for i in table.find({}): goodsdic = {'itemid':i['itemid'], 'sellerid':i['sellerid']} allgoods.append(goodsdic) print(allgoods)
然后构造爬取函数,构造函数前先要弄清它的json数据是怎么镶套的,弄清楚就好写代码了
def crawl_rank(itemid,sellerid): url = 'https://rate.tmall.com/list_detail_rate.htm?itemId={}&sellerId={}¤tPage={}' maxpage = get_page(itemid,sellerid) print(maxpage) for page in range(1,maxpage+1): try: header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36'} response = requests.get(url.format(itemid,sellerid,page),headers= header) html = response.text formaljson = html[15:] jsondata = json.loads(formaljson) items = jsondata['rateList'] for item in items: goodsrate = {'date':item['rateDate'], 'sku':item['auctionSku'], 'usernick':item['displayUserNick'], 'content':item['rateContent']} save_to_mongo(goodsrate) except: continue
然后是获取总页数的函数和存储到mongo数据库的函数,这里的总页数也可以在json中获取到
def save_to_mongo(goodsrate): try: if table2.insert(goodsrate): print('存储到MongoDB成功',goodsrate) except Exception: print('存储到MongoDB失败',goodsrate) def get_page(itemid,sellerid): try: url = 'https://rate.tmall.com/list_detail_rate.htm?itemId={}&sellerId={}¤tPage={}' header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36'} response = requests.get(url.format(itemid,sellerid,0), headers=header) html = response.text formaljson = html[15:] jsondata = json.loads(formaljson) return jsondata['paginator']['lastPage'] except: return get_page(itemid,sellerid) def main(): for i in range(len(allgoods)): goods = allgoods[i] print(goods) crawl_rank(goods['itemid'],goods['sellerid'])
运行main()试试看
这里有我的完整代码:github
到这里我们就大公告成了,以后有时间在研究下淘宝店铺的评论抓取
如果你对我的代码有什么疑问或者改进的地方,可以在评论里指出,大家互相交流才能取得进步,谢谢大家^^