Python利用selenium模拟用户操作抓取天猫评论数据

发表于:2017-8-17 11:51

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:弱虫    来源:博客

#
Python
分享:
  准备:
  python3.5
  安装selenium包
  第一种方法:
  cmd里输pip install selenium,但是经常报错
  第二种方法:
  下载安装包-cmd进入解压路径-python setup.py install-报错permission denied-右键安全更改报错文件夹权限为完全控制-再次安装成功
  unknown error: unable to discover open pages-下载chromedriver放在环境变量目录下
  测试自动打开百度时提示“您使用的是不受支持的命令行标记”-更改chromedriver版本为对应版本即可
  安装包下载地址:https://pypi.python.org/pypi/selenium
  chromedriver与chrome版本映射及下载地址:http://blog.csdn.net/huilan_same/article/details/51896672
  实现:
  selenium基本上就是模拟打开浏览器,向下滑动点击评论tab点击下一页等过程。由于selenium只能对显示在屏幕范围内的元素操作,所以滚动条操作很重要。
  def deal_recommends_infos(url):
      if not url.startswith('http'):
          url = 'https:' + url
      print('开始寻找评论:' + url)
      driver = webdriver.Chrome()
      driver.maximize_window() # 全屏 
      
      timeout = 30
      try:
          driver.get(url)
          WebDriverWait(driver, timeout).until(
              EC.presence_of_element_located((By.ID, "J_TabBarBox"))  # 判断页面是否初步加载成功的标记
          )
      except TimeoutException:
          print('宝贝链接未加载成功')
      try:
          # 页面上拉600,看到TabBarBox
          js = "window.scrollTo(0,600)"
          driver.execute_script(js)
      except WebDriverException:
          print('上拉寻找评论区时出现问题')
      time.sleep(2)
      # 点击累计评论TAB
      driver.find_element_by_xpath('//*[@id="J_TabBar"]/li[2]').click()
      time.sleep(4)
      print('成功点击累计评论TAB')
      try:
          # rate-grid的正则表达式
          driver.find_element_by_xpath('//*[@id="J_Reviews"]/div/div[6]')
      except NoSuchElementException:
          print('评论信息中元素还未加载')
      print('已经成功加载到评论区信息')
   
      for i in range(2):
          try:
              js = "window.scrollTo(0,2500)"
              driver.execute_script(js)
              time.sleep(2)
              # 点击下一页
              driver.find_element_by_css_selector('#J_Reviews > div > div.rate-page > div > a:last-child').click()
          
          except WebDriverException:    
              js = "window.scrollTo(0,3500)"
              driver.execute_script(js)
              time.sleep(2)
              # 点击下一页
              driver.find_element_by_css_selector('#J_Reviews > div > div.rate-page > div > a:last-child').click()
          except NoSuchElementException:
              print('找不到翻页按钮')
              continue
          print('已成功点击下一页')
          soup = BeautifulSoup(driver.page_source, "lxml")
          print(get_recommends_infos(soup))
          
      print('完成该链接的评论抓取') 
  要注意的点:
  浏览器要全屏,缺少这个操作的话很容易出现bug,我猜是因为天猫商城右下角的二维码妨碍了鼠标点击。
  下拉网页点击下一页时,由于天猫商城每页的评论长度不是那么确定,设置绝对值容易出现拉不到或者拉过了的情况,要做一个try语句。
  target = driver.find_element_by_css_selector('#J_Reviews > div > div.rate-page > div > a:last-child')
  driver.execute_script("arguments[0].scrollIntoView();",target) #拖动到可见的元素去
  我尝试用以上代码来滚动到指定元素可见,但是总报is not clickable at point (1030, 19). Other element would receive the click:查了下是被天猫商城那个手机购买的二维码挡住了……现在暂时没有解决方案,只能先拉2500,不够就再加个1000。
  理论上来说
  soup = BeautifulSoup(driver.page_source, "lxml")
  print(get_recommends_infos(soup))
  这两句应该是放在点击下一页之前的,但是不知道为啥这样就会出现把第一页抓取两遍的情况。神tm换下代码顺序就正常了,想不通为什么这样结果对,我再慢慢研究吧。
  #提取评论信息
  def get_recommends_infos(s):
      comment = s.find("div",class_="rate-grid")
      comment_data = comment.find_all("tr")
      lst1=[]
      #逐行读取
      for i in comment_data:
          goodstype_lst=[]
          username_lst=[]
          #comment1为初次评论,comment2为追加评论,reply1为商家初次回复,reply2为商家追加回复,goodstype为商品类型,username为用户名
          dic={'comment1': '','reply1':'','comment2': '','reply2':'', 'goodstype': goodstype_lst, 'username': username_lst} 
          try:
              content1=i.find('div',class_="tm-rate-premiere").find('div',class_="tm-rate-content")
              dic['comment1']=content1.text
          except:
              content1=i.find('div',class_="tm-rate-content").find('div',class_="tm-rate-fulltxt")
              dic['comment1']=content1.text
          try:
              content2=i.find('div',class_="tm-rate-append").find('div',class_="tm-rate-content")
              dic['comment2']=content2.text
          except:
              dic['comment2']='null'
          
          try:
              reply1=i.find('div',class_="tm-rate-premiere").find('div',class_="tm-rate-reply")
              dic['reply1']=reply1.text
          except:
              try:
                  reply2=i.find('div',class_="tm-rate-append").find('div',class_="tm-rate-reply")
                  dic['reply1']='null'
              except:
                  try:
                      reply1=i.find('div',class_="tm-rate-reply")
                      dic['reply1']=reply1.text
                  except:
                      dic['reply1']='null'
          try:
              reply2=i.find('div',class_="tm-rate-append").find('div',class_="tm-rate-reply")
              dic['reply2']=reply2.text
          except:
              dic['reply2']='null'
          goodstype=i.find('div',class_="rate-sku").find_all('p')
          for b in goodstype:
              goodstype_lst.append(b.attrs['title'])
          username=i.find_all('div',class_="rate-user-info")
          for c in username:
              username_lst.append(c.text)
          lst1.append(dic)        
      return lst1
  要注意的点:
  初次评论:如果有追加评论的话div会被分成class=tm-rate-premiere和tm-rate-append两块,这两块里面又分别有tm-rate-content,没有追加评论的情况下评论就是tm-rate-content一整块。因此直接用BeautifulSoup找tm-rate-content是有问题的,可能会找到两个评论。
  追加评论:这个比较好判断,没有tm-rate-append的话就没有追加评论
  初次回复:回复情况分为下表6种,其中有初次回复的分为1、2、5共3种,先通过find('div',class_="tm-rate-premiere").find('div',class_="tm-rate-reply")把1选出来了,剩下5种中,把3排除掉,第一个被找到的tm-rate-reply就是初次回复。
  追加回复:通过find('div',class_="tm-rate-append").find('div',class_="tm-rate-reply")把1、3选出来了,剩下的都为null
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号