4028574 发表于 2018-6-8 20:51

python爬去微博获得微博个人页面所有相关信息

本帖最后由 4028574 于 2018-6-8 21:07 编辑

本帖是为了承诺上一贴爬取微博
通过超找人名 选择对应的人名 进入进行所有内容的爬取 主要是 发布的消息 图片连接 视频连接 发布消息时的时间 以及设备 把这些信息全部保存下来只获得当前页面 操作起来非常简单应该很简单了
因为此次操作用的是浏览器模拟操作 不需要分析发包协议 只需要分析所有的页面内容即可程序运行会自动打开火狐浏览器 自动进行响应操作 操作完成后 会自动保存文件
如果有朋友会用数据库的 可以修改代码更改为数据包保存当前程序使用的是json保存在本地不是特别好看 但是所有的内容 是全的   
本来准备使用csv保存的 但是因为编码问题 不是特别好弄 所以放弃 直接使用json格式保存好了废话不多说 直接开搞

开发环境:kali Linux   python2.7
IDE: pycharm
第三方模块: selenium BeautifulSoup
火狐浏览器 最好是最新版本 不然 可能会调用失败
geckodriver 驱动 python调用火狐需要使用的驱动程序地址:https://github.com/mozilla/geckodriver/releases/      
正常来说 这个驱动下载下来需要添加环境变量 这个给个省事的解决方案把这个驱动 直接放进python的script文件夹中即可放入之后 用cmd直接打geckodriver 如果能出来下图这样 就说明配置成功然后就可以直接开启程序了

这里之所以选择使用浏览器模拟操作 是因为 直接发包会有微博的人机检测而且不是以.js为后缀的 所以他随时可能修改js的代码 这样可能会出现 这个帖子刚发出来没多久 js变了 大家就找不到新的值了 就陷入僵局 用这个模拟的方法 就完全不用顾忌他的js因为浏览器会自动解析js我们只管直接抓取 我们需要的页面内容即可这样也降低了难度


说明一下 本程序是在kali linux下调试通过 没有任何问题如果在win的控制台下操作出现问题 请自己想办法修改控制台的编码为utf-8 就不会有错误了
下面是成品图   因为是json格式 排版比较乱 所以最好是直接存入数据库这样就比较好看点这个的图截图不到位 因为比较长 后面还有图片的详细地址


好了 直接上代码需要搜索谁就去搜索谁吧
代码中注释的地方是火狐的无头模式如果有了解的朋友 可以直接尝试下
#!/usr/bin/evn python
# -*- coding: utf-8 -*-

from urllib import quote,unquote
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import json
from time import sleep
import re
import codecs

class Weibo(object):
    def __init__(self,url=""):
      self.url = url
      #firefoxoption = webdriver.FirefoxOptions()
      #firefoxoption.set_headless()
      #self.browser = webdriver.Firefox(firefox_options=firefoxoption)
      print("正在打开浏览器,请稍后...")
      self.browser = webdriver.Firefox()

    def GetPageSource(self,url,mate,callback):
      print("正在打开网页,请稍后...")
      self.browser.get(url)
      wait = WebDriverWait(self.browser,10)
      userInfo = wait.until(EC.presence_of_element_located(mate))
      return callback(self.browser.page_source)

    def GetUserList(self,url):
      print ("正在获得找人页面所有匹配到的信息,请稍后...")
      retUserList = []
      bs = BeautifulSoup(url,"lxml")
      userList = bs.select("#pl_user_feedList .list_person")
      for user in userList:
            userInfo = {
                "nickName":user.select(".person_name").a['title'],
                "mainPage":"https:" + user.select(".person_name").a['href'],
                "Address":user.select(".person_addr > span:nth-of-type(2)").get_text(),
                "Card": user.select(".person_card").get_text(strip=True) if user.select(".person_card") else "",
                "Num": " ".join(user.select(".person_num").get_text().lstrip().split("\n")),
                "PersonInfo":re.sub("[\t\n]","",user.select(".person_info").get_text())
            }
            retUserList.append(userInfo)
      return retUserList

    def GetPersonPageContent(self,url):
      print("正在或者个人页面信息,请稍后")
      bs = BeautifulSoup(url,"lxml")
      contentList = bs.select("div > div")
      retPersonInfoList = []
      for i in xrange(len(contentList)) :
            try:
                contentInfo = {
                  "id": str(i+1),
                  "from":contentList.select(".WB_from").get_text(strip=True),
                  "text":contentList.select(".WB_text.W_f14").get_text(strip=True),
                  "videoOrImg":self.GetImageOrVideoPath(contentList.select(".WB_media_wrap")) if contentList.select(".WB_media_wrap") else ""
                }
                retPersonInfoList.append(contentInfo)
            except:
                continue
      return retPersonInfoList


    def GetImageOrVideoPath(self,source):
            media = source.select(".WB_media_a")
            url = media.select(".WB_video")
            if url:
                videoPath = unquote(unquote(url["video-sources"]))
                return videoPath
            else:
                try:
                  actionData = media["action-data"]
                  if actionData :
                        if "pic_ids" in actionData:
                            data = re.search("clear_picSrc=(.*?)&", actionData)
                            imageList = [ "https:%s"%(unquote(img)) for img in data.group(1).split(",")]
                            return ",".join(imageList)
                        else:
                            data = re.search("clear_picSrc=(.*?)$", actionData)
                            return "https:" + unquote(data.group(1))
                except KeyError as e:
                  imagePath = media.select(".WB_pic").a.img["src"]
                  return imagePath


    def SavePersonInfo(self,filename,content):
      with codecs.open("./%s.json" % filename, "w+", "utf-8") as f:
            for i in content:
                f.write(json.dumps(i) + "\n")

    def run(self,url):
      userList = self.GetPageSource(url,(By.ID,"pl_user_feedList"),self.GetUserList)
      if userList:
            for i in xrange(len(userList)) :
                print ("%d:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n"%(i+1,userList["nickName"],userList["mainPage"],userList["Address"],userList["Card"],userList["Num"],userList["PersonInfo"]))
      else:
            return -1
      while True:
            try:
                inputcontent = int(raw_input("请在上面输出的内容中选择需要的选项 1-%d: "%len(userList)))
                if inputcontent > 0 and inputcontent <= len(userList):
                  break
                print("请输入数字的范围 1 - %d "%len(userList))
            except:
                print("请输入数字的范围 1 - %d "%len(userList))
                continue
      self.browser.execute_script("window.open()")
      self.browser.switch_to_window(self.browser.window_handles)
      userInfo = self.GetPageSource(userList["mainPage"],(By.CSS_SELECTOR,"div"),self.GetPersonPageContent)
      if userInfo :
            self.SavePersonInfo(userList["nickName"],userInfo)

    def __del__(self):
      if self.browser.window_handles:
            for hand in self.browser.window_handles:
                self.browser.switch_to_window(hand)
                self.browser.close()

def main():
    name= raw_input("请输入需要搜索的名字 : ")
    name = quote(quote(name))
    url ="http://s.weibo.com/user/%s&Refer=index"%name
    weiboret = Weibo()
    weiboret.run(url)


if __name__ == '__main__':
    main()

4028574 发表于 2018-6-11 10:58

154675361 发表于 2018-6-11 08:51
楼主,能告诉一下window下怎么设置编码吗,网上搜了一堆没用,谢谢了
可能是代码开头改一下 就可以了吧
#coding:utf-8
我也不知道 行不行 你可以试下

hycq120 发表于 2018-6-8 21:15

高手楼主

kk1212 发表于 2018-6-8 21:22

厉害,真是灵活。

Dlan 发表于 2018-6-8 21:33

可以,我喜欢

Dlan 发表于 2018-6-8 21:35

我还是喜欢抓包,直接访问接口,再加上多IP

上官轩墨 发表于 2018-6-8 22:38

楼主这是要安装多少个库?,新手,没安装库,应该不能运行吧

154675361 发表于 2018-6-8 23:50

感谢楼主,拿走学习了,nice

chen4321 发表于 2018-6-9 07:03

谢谢分享,学习了

servicelabs 发表于 2018-6-9 09:11

不错,直接copy保存了!

154675361 发表于 2018-6-11 08:51

楼主,能告诉一下window下怎么设置编码吗,网上搜了一堆没用,谢谢了
页: [1] 2
查看完整版本: python爬去微博获得微博个人页面所有相关信息