环境:
- BeautifulSoup4 (4.6.0)
- requests (2.19.1)
分析
该博客是本人第一个爬虫项目,之前比较懒,没上传博客,最近再学爬虫,在此一并补上。
我们知道,爬虫获取数据的思路是: 先根据初始(初始id)的网页,筛选需要的网页,并把需要的网页url(用户id)加入到队列中,然后每次队列中取出一个网页,按初始页面的方式爬取,如此循环,即可获取大量的数据。
根据这个思路,我们猜想能否利用微博关注的人页面获取新用户,检查新检索用户的个人信息是否满足我们要找的地区,或者上学经历中是否有我们需要的,如果有需要的,则将它加入队列,最后循环爬取,将所有
根据这个思路,我们猜想能否利用微博关注的人页面获取新用户,将地区(青岛)和学校作为筛选条件,满足条件作为可能认识的人,打印并保存其信息。按照如下流程循环,即可获得大量可能认识的人,然后我们可以对输出url进行手动访问,判断是否认识,认识则直接关注,岂不是美滋滋。
程序代码
# -*- coding:utf-8 -*-
__author__ = 'cck'
import requests
from bs4 import BeautifulSoup
import time
import pickle
from collections import deque
import random
import os
import copy
'''
注意事项:
1.工程文件夹下创建一个名为“中断数据保存”的文件夹
2.文件中存的内容分别是什么?
user_info(字典):用来存放爬取的信息
id_q(队列):查找结果的队列
url_follow(队列):待筛选的关注者队列
all_follow_id(列表):用来存放已经找过的用户id
info(字典):存放用户的url、个人简介、相册等信息(待完善)
3.cookie需要登录你的微博,之后按F12,在network里面获取
4.**的地方需要改成你的数据
'''
def td_has_style(tag): # 查找
return tag.has_attr('style') and tag.name == 'td'
class wb_crawler:
def __init__(self):
# q_tmp = deque()
#改成你的cookie
self.cookie = 'SCF=Ak-lTM1OIUxitjlcbC102f4RV5bUzvlzNPmYEHtdKxQFi6HJ17pwXg8cdHluXpTKngC6rOi8t-PguOqHoq5u0nY.; _T_WM=c23559ac343eca2d7a4b434339a62175; SUB=_2A25xQ5AJDeRhGeBO7VAU8ijMwj6IHXVSzzBBrDV6PUJbkdAKLWzDkW1NRchsyxcMaxDpKy8hAohQWmkFs3yrRJ_L; SUHB=0xnyVXOmVrN3C7; SSOLoginState=1548214361'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
'Cookie': self.cookie
}
self.user_info = dict() # 用来存放爬取的信息
self.id_q = deque() # 查找结果队列
self.url_follow = deque() # 待判断的关注者队列
self.all_follow_id = [] # 用来存放已经找过的用户id
self.f = open('中断数据保存/output.txt', 'a') # 用来存放所有输出信息
self.info = {
'url': '',
'comment': '',
'album': '',
'info': ''
}
self.user_id = 0 # 初始用户id,
print('输入1:重新开始(!将删除所有以前数据!)\n输入2: 继续上次')
a = input()
print(a)
if os.path.getsize('中断数据保存/id_q.txt') > 0 and a == '2': # 说明有数据,需要读取新数据,不需要初始user
print('正在加载上次保存数据!')
with open('中断数据保存/id_q.txt', 'rb') as file:
self.id_q = pickle.loads(file.read())
with open('中断数据保存/url_follow.txt', 'rb') as file:
self.url_follow = pickle.loads(file.read())
with open('中断数据保存/all_follow_id.txt', 'rb') as file:
self.all_follow_id = pickle.loads(file.read())
print('加载成功!')
#继续中断前的操作^^^^
elif a == '1' or os.path.getsize('中断数据保存/id_q.txt') == 0 :#否则指定初始user进行操作
print('正在初始化!')
self.clear_all()
#使用你的初始用户
self.user_id = ** #爬取第一个用户的id,该id一定是满足筛选条件的,你认识的人
self.id_q.append(self.user_id)#
self.all_follow_id.append(self.user_id)
print('初始化成功!')
def clear_all(self):
##把所有存取在硬盘中的数据清除掉,即将all_follow_id.txt等文件内容清空
with open('中断数据保存/all_follow_id.txt', 'wb') as f1:
f1.truncate()
with open('中断数据保存/url_follow.txt', 'wb') as f2:
f2.truncate()
with open('中断数据保存/id_q.txt', 'wb') as f3:
f3.truncate()
with open('中断数据保存/user_info.txt', 'wb') as f4:
f4.truncate()
with open('中断数据保存/output.txt', 'wb') as f5:
f5.truncate()
#中断数据的保存,方便下次继续上次位置爬取
def save_all(self):#每次找到新用户即调用保存
pickle.dump(self.all_follow_id, open('中断数据保存/all_follow_id.txt', 'wb'))
pickle.dump(self.url_follow, open('中断数据保存/url_follow.txt', 'wb'))
pickle.dump(self.id_q, open('中断数据保存/id_q.txt', 'wb'))
pickle.dump(self.user_info, open('中断数据保存/user_info.txt', 'wb'))
def get_html(self,url, headers): # 由个人cookies模拟访问网站,获取网站的html
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
except:
print('爬取{}出错,可能被封ip,正在保存当前数据!', url)
#保存信息并退出
self.save_all()
print('保存成功!')
# sys.exit()
return ''
return response.content
def get_id(self,lxml): # 根据主页的html获取该网页对应用户id
soup = BeautifulSoup(lxml, "lxml")
div = soup.find('div', 'tip2')
u = div.find('a').get('href')
id = u.split('/')
return id[1] # 获取id
def find_region(self,lxml): # 传入个人信息页面,判断地区学校等是否为你需要的
soup = BeautifulSoup(lxml, "lxml")
count = 1
for div in soup.find_all('div', 'c'):
if count == 4: # 找到个人信息的标签部分
if (div.get_text().find('**') != -1): # 判断地区
print(div.get_text()) # 测试正误
self.info['info'] = div.get_text()
print(self.info)
print('找到可能认识的人!地址为:')
return True
else:
print(div.get_text())#test
if count == 5:
if (div.get_text().find('**') != -1): # 判断学校
print(div.get_text()) # 测试正误
self.info['info'] = div.get_text()
print('找到可能认识的人!地址为:')
return True
count += 1
return False
def get_follow(self,lxml): # 将新用户的关注者主页提取并加入队列
soup = BeautifulSoup(lxml, "lxml")
# f = open('output.txt','wb+')
# f.write(lxml)
# f.close()
for td in soup.find_all(td_has_style): # 获取该用户所有的关注的人,并加入爬取队列
# print(td.find('a').get('href'))
# td.find('a').get('href')
self.url_follow.append(td.find('a').get('href'))
def run(self):
self.f.close()
url = ''
lxml = ''
while len(self.id_q) != 0:
print('now len of id_q is %d' % len(self.id_q)) # 测 试
self.user_id = self.id_q.popleft() #从队列中获取一个用户
url_root = "https://weibo.cn/%d" % self.user_id # 构造主页
# lxml = self.get_html(url,self.headers)# 访问主页获取lxml, 爬 1
# self.user_id = (int)(self.get_id(lxml)) # 爬取用户id
# # 1.id_q,读取其所有的follow加入follow队列,重复检测(list)
# url = "https://weibo.cn/%d" % self.user_id #构造主页
for page_count in range(1,21):
#只爬取1-20页
print('now catching page %d,root url: %s' % (page_count,url_root))
url_follow = url_root + '/fans?page=%d' % page_count
lxml_follow = self.get_html(url_follow,self.headers)# 抓取关注的人获取followlxml, 爬 1
self.get_follow(lxml_follow)#读取加入follow队列
# 2.分别爬取follow队列用户的info信息,筛选,并把满足要求的加入id_q
while len(self.url_follow) != 0:
url = self.url_follow.popleft()
print('scaning url:'+url)
lxml = self.get_html(url,self.headers)# 爬2 爬取主页
self.user_id = (int)(self.get_id(lxml))
#id存在则跳过该id
if self.user_id in self.all_follow_id:
continue
self.all_follow_id.append(self.user_id)
url = "https://weibo.cn/%d" % self.user_id # 构造主页
url_info = url + '/info'
lxml_info = self.get_html(url_info,self.headers)# 爬3 爬取信息页
if self.find_region(lxml_info):#满足要求加入id_q
self.id_q.append(self.user_id)
#out
str_out = "https://weibo.com/%d" % self.user_id
print(str_out)
# 获取信息
self.info['url'] = str_out
print(self.info)#test and will soon be deleted
info_copy = copy.deepcopy(self.info)
self.user_info[self.user_id] = info_copy#待修改,要求保存所有用户信息1.每次都加载上次的
print(self.user_info) #
#保存输出
self.f = open('中断数据保存/output.txt', 'a')
self.f.write(str_out+'\n')
self.f.close()
self.save_all()
self.info.clear()
# time.sleep(3)
time.sleep(random.randint(2,6))#爬取一个之后,随机等待2-6秒
if __name__ == '__main__':
crawler = wb_crawler()
crawler.run()
cookie获取如图:
结果:
效果还不错。
写在最后
因为静态微博页面的爬取比较简单,第一次做的时候选择了使用静态页面,风格比较简陋,但也算是数据成功爬取到了吧。