【Python应用】寻找社交网络中的目标用户
日后的更新:由于是很久以前的课程设计项目,完整的源码已经不见了,关键的网页数据获取和解析的部分代码我在文章中已经贴出来了,但写的也不够好,如果想参考爬取知乎的同学,推荐去看慕课网的《python分布式爬虫打造搜索引擎》,其中有对编写知乎爬虫的视频讲解,虽然已经过去了不短的时间,知乎的反爬策略可能有变,但还是有参考价值的。
对于爬虫动态代理池的构建,推荐qiyeboy/IPProxyPool这个开源项目,安装的时候可能有点麻烦,见到错误提示缺少哪个包手动pip install就好了。
以下是正文:
这是我们学校的软件工程课程设计的题目,要求自行编写爬虫或者利用开放的API获取新浪微博、知乎等社交网站的用户信息,利用数据挖掘的相关算法进行分析, 从大规模的用户群体中, 分别找出其中具有海淘或母婴购物意向的用户。
在具体实现方面我选择了知乎作为目标的社交网站,通过Python编写数据爬虫与进行数据的分析,通过数据建立用户特征向量,将已知具有母婴购物倾向的用户与未知购物倾向的用户的特征向量进行对比,进而寻找出具有母婴购物倾向的用户。
###目录
编程前简单的分析
###选择知乎的原因
知乎的个人详情页与问题详情页不需要登陆也能访问,免除了模拟登陆的步骤。
在知乎无论是问题描述还是个人信息内,标签的使用频繁,能给后续的文本处理与分析带来极大地方便。
不足之处:知乎专业化程度较高,其在生活化气息不如新浪微博等社交网站。
选定需要获取的信息
从个人信息页面与问题详情页面分析我们的爬虫应该爬取的信息:
来逐项考虑每项信息对我们项目的意义:
-
用户的基本信息——昵称、居住地、教育程度等,一般考虑并不会对是否具有母婴购物倾向具有决定性的影响。
-
用户关注的话题、问题、专栏——关注的话题能最直观的展现用户的喜好、关注点所在,专栏与话题有重叠,关注的问题数量不同用户间可能会差距较大。
-
用户的回答,专栏——可以反映用户的特长,不能反映用户的兴趣点。
-
用户的提问——可能能反映用户的某种需求。问题tag能对问题进行有效概括。
综上,我决定对每个用户提取其关注的话题与所提的问题、问题的tag来建立用户特征向量。
##爬虫的编写
爬虫选择了使用Python编写,主要使用了其中的requests, beautifulsoup等库。
###一些难点与解决方法
爬虫实现过程中遇到的一些阻碍与大体解决方法如下
-
直接爬虫访问知乎遇到了500错误,结合chrome的开发者工具与fiddle网络分析工具,分析对知乎进行访问的网络请求,在爬虫头部加入了伪造的请求头。
-
前端知识较为缺乏,对HTML的DOM树结构了解不够深入,对beautifulsoup库不能很好的利用,对一些内容的爬取还需结合正则表达式来操作。
-
在获取母婴用品话题的关注用户的时候无法绕过登陆过程,而且需要对动态的网页内容进行爬取,此时只能通过selenium+chrome的组合自动填入登陆表单信息与下拉滚动条获取用户id,手动点击验证码的方式完成(现在知乎的登陆验证是点击图中的倒立文字,完全自动化的爬虫想必很难处理)。
-
对于知乎会限制固定ip访问频率的问题,通过在网上批量购买ip代理地址、建立ip代理池解决,但ip代理池的更新还没能做到自动化。
-
对于单个爬虫爬取效率太低的问题,由于爬虫完整运行一次的时间主要由网络延迟决定,所以使用python的多线程编程爬虫提高爬取效率。
-
爬取的数据同步存储到mysql数据库中,使用python的pymysql库对数据库进行操作。
爬虫的大致结构
爬虫工作分为三个阶段:第一阶段为随机获取一定数量的用户id,第二阶段为获取一定数量已知具有母婴购物倾向的用户id,第三阶段为根据已经获取的用户id去获取用户的个人信息与提问详情。
-
第一阶段的工作中,以随机的一位用户作为种子用户,获取其关注的20位用户id,对这20位用户再获取其每个人关注的20位用户,如此循环,预计获取8000位用户作为未知购物倾向的用户组,将用户id写入数据库中。
-
第二阶段的工作中,前往知乎“母婴用品”话题关注者页面,获取页面下1500名关注者,作为已知具有母婴购物倾向的用户的用户组,同样将用户id写入数据库中。
-
第三阶段的工作中,通过数据库中的用户id,获取其关注的话题列表与已经提问的问题的标签列表。
其中第三阶段,也是爬虫主要阶段的主要代码如下:
# -*- coding:utf-8 -*-
from bs4 import BeautifulSoup
import requests
import re
import pymysql
import threading
import queue
import time
#用于保存用户uid在数据库中序号的队列
q = queue.Queue(maxsize=3000)
conn_0 = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root',
db='zhihu', charset='utf8')
cursor_0 = conn_0.cursor()
#将未读取过的用户入列
sql_0 = 'SELECT order_number from infant_userid where is_read = 0'
cursor_0.execute(sql_0)
conn_0.commit()
for r in cursor_0:
r = re.sub("\D", "", str(r))
print(r)
q.put(r)
class zhihu():
def __init__(self):
# 连接数据库
self.conn = pymysql.connect(host='127.0.0.1', port=3306, user='', passwd='',
db='zhihu', charset='utf8')
self.main_url = 'https://www.zhihu.com/people/'
self.answers_url = '/answers'