├── .gitattributes
├── .gitignore
├── README.md
└── 微博爬虫.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization2
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .nox/
42 | .coverage
43 | .coverage.*
44 | .cache
45 | nosetests.xml
46 | coverage.xml
47 | *.cover
48 | .hypothesis/
49 | .pytest_cache/
50 |
51 | # Translations
52 | *.mo
53 | *.pot
54 |
55 | # Django stuff:
56 | *.log
57 | local_settings.py
58 | db.sqlite3
59 |
60 | # Flask stuff:
61 | instance/
62 | .webassets-cache
63 |
64 | # Scrapy stuff:
65 | .scrapy
66 |
67 | # Sphinx documentation
68 | docs/_build/
69 |
70 | # PyBuilder
71 | target/
72 |
73 | # Jupyter Notebook
74 | .ipynb_checkpoints
75 |
76 | # IPython
77 | profile_default/
78 | ipython_config.py
79 |
80 | # pyenv
81 | .python-version
82 |
83 | # celery beat schedule file
84 | celerybeat-schedule
85 |
86 | # SageMath parsed files
87 | *.sage.py
88 |
89 | # Environments
90 | .env
91 | .venv
92 | env/
93 | venv/
94 | ENV/
95 | env.bak/
96 | venv.bak/
97 |
98 | # Spyder project settings
99 | .spyderproject
100 | .spyproject
101 |
102 | # Rope project settings
103 | .ropeproject
104 |
105 | # mkdocs documentation
106 | /site
107 |
108 | # mypy
109 | .mypy_cache/
110 | .dmypy.json
111 | dmypy.json
112 |
113 | # Pyre type checker
114 | .pyre/
115 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 前言
2 |
3 | 为什么写这个博客,主要是CSDN上有几个比较热的微博爬虫,基本在今年都挂掉了用不了。比如 《微博爬虫,每日百万级数据》,博主写的比较全,不过因为今年微博查的更严了,所以每日百万级的基本不太可能(除非有很多账号,然而淘宝上的微博账号也涨价了,要达到这么大的数据量都够买一块RTX2080了)。
4 |
5 | 所以基于一些爬虫框架,这篇博客给出的是更加简单易懂的轻量级微博爬虫,对于学校实验、数据测试、NLP模型训练是大概够用的,原文见
6 | 我的博客:https://blog.csdn.net/qq_39521554/article/details/87940001
7 |
8 |
9 | *说明:这个轻量级爬虫每次爬取内容大概在每个ID100条左右(可以设置的更大),只需要建立超过一个较大的微博ID列表(这个表可以自己爬或者网上找)然后随机选取一部分用户进行爬取即可。同一IP每日建议不超过10万条,以免被封。
10 |
11 | 此外有条件的可以用分布式爬虫扩展一下,如果对于数据量需求不高的则此版本即可。
12 |
13 |
14 |
15 | ## 安装环境
16 |
17 | -本项目Python版本为Python3.6
18 |
19 | -selenium
20 |
21 | -BeautifulSoup v4
22 |
23 | git clone git@github.com:Y1ran/Weibo_Light_Spyder_2019.git
24 | cd WeiboSpider
25 | pip install -r requirements.txt
26 |
27 |
28 | ## 步骤简介
29 |
30 | ### 1.选取爬取目标网址
31 |
32 | 首先,在准备开始爬虫之前,得想好要爬取哪个网址。新浪微博的网址分为网页端和手机端两个,大部分爬取微博数据都会选择爬取手机端,因为对比起来,手机端基本上包括了所有你要的数据,并且手机端相对于PC端是轻量级的。
33 | 下面是GUCCI的手机端和PC端的网页展示。
34 |
35 |

36 |
37 |
38 | ### 2.模拟登陆
39 |
40 | 定好爬取微博手机端数据之后,接下来就该模拟登陆了。
41 | 模拟登陆的网址和登陆的网页下面的样子
42 | 
43 |
44 |
45 |
46 | ### 3.获取用户微博页码
47 |
48 | 在登录之后可以进入想要爬取的商户信息,因为每个商户的微博量不一样,因此对应的微博页码也不一样,这里首先将商户的微博页码爬下来。与此同时,将那些公用信息爬取下来,比如用户uid,用户名称,微博数量,关注人数,粉丝数目
49 | 
50 |
51 |
52 |
53 | ### 4.根据爬取的最大页码,循环爬取所有数据
54 | 在得到最大页码之后,直接通过循环来爬取每一页数据。抓取的数据包括,微博内容,转发数量,评论数量,点赞数量,发微博的时间,微博来源,以及是原创还是转发。
55 |
56 |
57 | 在得到所有数据之后,可以写到csv文件,或者excel
58 |
59 | 
60 |
61 |
--------------------------------------------------------------------------------
/微博爬虫.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Tue Feb 26 18:02:56 2019
4 |
5 | @author: Administrator
6 | """
7 |
8 | from selenium import webdriver
9 | from bs4 import BeautifulSoup
10 | import numpy as np
11 | from scipy import *
12 | import time
13 |
14 | browser = webdriver.Chrome()
15 | #browser = webdriver.Firefox()
16 |
17 | """test"""
18 | browser.get("http://www.baidu.com")
19 | print(browser.page_source)
20 | browser.close()
21 |
22 |
23 | def simulate_logging():
24 | try:
25 | print(u'登陆新浪微博手机端...')
26 | ##打开Firefox浏览器
27 | browser = webdriver.Firefox()
28 | ##给定登陆的网址
29 | url = 'https://passport.weibo.cn/signin/login'
30 | browser.get(url)
31 | time.sleep(3)
32 | #找到输入用户名的地方,并将用户名里面的内容清空,然后送入你的账号
33 | username = browser.find_element_by_css_selector('#loginName')
34 | time.sleep(2)
35 | username.clear()
36 | username.send_keys('****')#输入自己的账号
37 | #找到输入密码的地方,然后送入你的密码
38 | password = browser.find_element_by_css_selector('#loginPassword')
39 | time.sleep(2)
40 | password.send_keys('ll117117')
41 | #点击登录
42 | browser.find_element_by_css_selector('#loginAction').click()
43 | ##这里给个15秒非常重要,因为在点击登录之后,新浪微博会有个九宫格验证码,下图有,通过程序执行的话会有点麻烦(可以参考崔庆才的Python书里面有解决方法),这里就手动
44 | time.sleep(15)
45 | except:
46 | print('########出现Error########')
47 | finally:
48 | print('完成登陆!')
49 |
50 | def spyder_weibo():
51 | #本文是以GUCCI为例,GUCCI的用户id为‘GUCCI’
52 | id = 'GUCCI'
53 | niCheng = id
54 | #用户的url结构为 url = 'http://weibo.cn/' + id
55 | url = 'http://weibo.cn/' + id
56 | browser.get(url)
57 | time.sleep(3)
58 | #使用BeautifulSoup解析网页的HTML
59 | soup = BeautifulSoup(browser.page_source, 'lxml')
60 | #爬取商户的uid信息
61 | uid = soup.find('td',attrs={'valign':'top'})
62 | uid = uid.a['href']
63 | uid = uid.split('/')[1]
64 | #爬取最大页码数目
65 | pageSize = soup.find('div', attrs={'id': 'pagelist'})
66 | pageSize = pageSize.find('div').getText()
67 | pageSize = (pageSize.split('/')[1]).split('页')[0]
68 | #爬取微博数量
69 | divMessage = soup.find('div',attrs={'class':'tip2'})
70 | weiBoCount = divMessage.find('span').getText()
71 | weiBoCount = (weiBoCount.split('[')[1]).replace(']','')
72 | #爬取关注数量和粉丝数量
73 | a = divMessage.find_all('a')[:2]
74 | guanZhuCount = (a[0].getText().split('[')[1]).replace(']','')
75 | fenSiCount = (a[1].getText().split('[')[1]).replace(']', '')
76 |
77 | #通过循环来抓取每一页数据
78 | for i in range(1, pageSize+1): # pageSize+1
79 | #每一页数据的url结构为 url = 'http://weibo.cn/' + id + ‘?page=’ + i
80 | url = 'https://weibo.cn/GUCCI?page=' + str(i)
81 | browser.get(url)
82 | time.sleep(1)
83 | #使用BeautifulSoup解析网页的HTML
84 | soup = BeautifulSoup(browser.page_source, 'lxml')
85 | body = soup.find('body')
86 | divss = body.find_all('div', attrs={'class': 'c'})[1:-2]
87 | for divs in divss:
88 | # yuanChuang : 0表示转发,1表示原创
89 | yuanChuang = '1'#初始值为原创,当非原创时,更改此值
90 | div = divs.find_all('div')
91 | #这里有三种情况,两种为原创,一种为转发
92 | if (len(div) == 2):#原创,有图
93 | #爬取微博内容
94 | content = div[0].find('span', attrs={'class': 'ctt'}).getText()
95 | aa = div[1].find_all('a')
96 | for a in aa:
97 | text = a.getText()
98 | if (('赞' in text) or ('转发' in text) or ('评论' in text)):
99 | #爬取点赞数
100 | if ('赞' in text):
101 | dianZan = (text.split('[')[1]).replace(']', '')
102 | #爬取转发数
103 | elif ('转发' in text):
104 | zhuanFa = (text.split('[')[1]).replace(']', '')
105 | #爬取评论数目
106 | elif ('评论' in text):
107 | pinLun = (text.split('[')[1]).replace(']', '')
108 | #爬取微博来源和时间
109 | span = divs.find('span', attrs={'class': 'ct'}).getText()
110 | faBuTime = str(span.split('来自')[0])
111 | laiYuan = span.split('来自')[1]
112 |
113 | #和上面一样
114 | elif (len(div) == 1):#原创,无图
115 | content = div[0].find('span', attrs={'class': 'ctt'}).getText()
116 | aa = div[0].find_all('a')
117 | for a in aa:
118 | text = a.getText()
119 | if (('赞' in text) or ('转发' in text) or ('评论' in text)):
120 | if ('赞' in text):
121 | dianZan = (text.split('[')[1]).replace(']', '')
122 | elif ('转发' in text):
123 | zhuanFa = (text.split('[')[1]).replace(']', '')
124 | elif ('评论' in text):
125 | pinLun = (text.split('[')[1]).replace(']', '')
126 | span = divs.find('span', attrs={'class': 'ct'}).getText()
127 | faBuTime = str(span.split('来自')[0])
128 | laiYuan = span.split('来自')[1]
129 |
130 | #这里为转发,其他和上面一样
131 | elif (len(div) == 3):#转发的微博
132 | yuanChuang = '0'
133 | content = div[0].find('span', attrs={'class': 'ctt'}).getText()
134 | aa = div[2].find_all('a')
135 | for a in aa:
136 | text = a.getText()
137 | if (('赞' in text) or ('转发' in text) or ('评论' in text)):
138 | if ('赞' in text):
139 | dianZan = (text.split('[')[1]).replace(']', '')
140 | elif ('转发' in text):
141 | zhuanFa = (text.split('[')[1]).replace(']', '')
142 | elif ('评论' in text):
143 | pinLun = (text.split('[')[1]).replace(']', '')
144 | span = divs.find('span', attrs={'class': 'ct'}).getText()
145 | faBuTime = str(span.split('来自')[0])
146 | laiYuan = span.split('来自')[1]
147 | time.sleep(2)
148 | print(i)
149 |
150 | if __name__ == '__main__':
151 |
152 | simulate_logging()
153 | spyder_weibo()
154 |
155 | print("spyder finished!")
156 |
--------------------------------------------------------------------------------