想爬虫知乎的东西,学哪个语言学 知乎好?

o &nbsp,&nbsp&nbsp,&nbsp&nbsp,&nbsp
PHP多进程实现的抓取知乎用户程序,仅用一天时间就抓了知乎一百万用户
爬虫代码 可否共享下啊
关于伯乐头条
专注于IT互联网,分享业界最新动态。
新浪微博:
推荐微信号
(加好友请注明来意)
- 好的话题、有启发的回复、值得信赖的圈子
- 分享和发现有价值的内容与观点
- 为IT单身男女服务的征婚传播平台
- 优秀的工具资源导航
- 翻译传播优秀的外文文章
- 国内外的精选博客文章
- UI,网页,交互和用户体验
- 专注iOS技术分享
- 专注Android技术分享
- JavaScript, HTML5, CSS
- 专注Java技术分享
- 专注Python技术分享
& 2017 伯乐在线零基础写Java知乎爬虫之先拿百度首页练练手
投稿:hebedich
字体:[ ] 类型:转载 时间:
本来打算这篇文章直接抓取知乎的,但是想想还是先来个简单的吧,初级文章适合初学者,高手们请直接略过
上一集中我们说到需要用Java来制作一个知乎爬虫,那么这一次,我们就来研究一下如何使用代码获取到网页的内容。
首先,没有HTML和CSS和JS和AJAX经验的建议先去W3C(点我点我)小小的了解一下。
说到HTML,这里就涉及到一个GET访问和POST访问的问题。
如果对这个方面缺乏了解可以阅读W3C的这篇:《GET对比POST》。
啊哈,在此不再赘述。
然后咧,接下来我们需要用Java来爬取一个网页的内容。
这时候,我们的百度就要派上用场了。
没错,他不再是那个默默无闻的网速测试器了,他即将成为我们的爬虫小白鼠!~
我们先来看看百度的首页:
相信大家都知道,现在这样的一个页面,是HTML和CSS共同工作的结果。
我们在浏览器中右击页面,选择“查看页面源代码”:
没错,就是这一坨翔一样的东西。这就是百度页面的源代码。
接下来我们的任务,就是使用我们的爬虫也获取到一样的东西。
先来看一段简单的源码:
import java.io.*;import java.net.*;public class Main {&public static void main(String[] args) {&&// 定义即将访问的链接&&String url = "";&&// 定义一个字符串用来存储网页内容&&String result = "";&&// 定义一个缓冲字符输入流&&BufferedReader in =&&try {&&&// 将string转成url对象&&&URL realUrl = new URL(url);&&&// 初始化一个链接到那个url的连接&&&URLConnection connection = realUrl.openConnection();&&&// 开始实际的连接&&&connection.connect();&&&// 初始化 BufferedReader输入流来读取URL的响应&&&in = new BufferedReader(new InputStreamReader(&&&&&connection.getInputStream()));&&&// 用来临时存储抓取到的每一行的数据&&&S&&&while ((line = in.readLine()) != null) {&&&&//遍历抓取到的每一行并将其存储到result里面&&&&result +=&&&}&&} catch (Exception e) {&&&System.out.println("发送GET请求出现异常!" + e);&&&e.printStackTrace();&&}&&// 使用finally来关闭输入流&&finally {&&&try {&&&&if (in != null) {&&&&&in.close();&&&&}&&&} catch (Exception e2) {&&&&e2.printStackTrace();&&&}&&}&&System.out.println(result);&}}
以上就是Java模拟Get访问百度的Main方法,
可以运行一下看看结果:
啊哈,和我们前面用浏览器看到的一模一样。至此,一个最最简单的爬虫就算是做好了。
但是这么一大坨东西未必都是我想要的啊,怎么从中抓取出我想要的东西呢?
以百度的大爪子Logo为例。
临时需求:
获取百度Logo的大爪子的图片链接。
先说一下浏览器的查看方法。
鼠标对图片右击,选择审查元素(火狐,谷歌,IE11,均有此功能,只是名字不太一样):
啊哈,可以看到在一大堆div的围攻下的可怜的img标签。
这个src就是图像的链接了。
那么在java中我们怎么搞呢?
事先说明,为了方便演示代码,所有代码均未作类封装,还请谅解。
我们先把前面的代码封装成一个sendGet函数:
import java.io.*;import java.net.*;public class Main {&static String sendGet(String url) {&&// 定义一个字符串用来存储网页内容&&String result = "";&&// 定义一个缓冲字符输入流&&BufferedReader in =&&try {&&&// 将string转成url对象&&&URL realUrl = new URL(url);&&&// 初始化一个链接到那个url的连接&&&URLConnection connection = realUrl.openConnection();&&&// 开始实际的连接&&&connection.connect();&&&// 初始化 BufferedReader输入流来读取URL的响应&&&in = new BufferedReader(new InputStreamReader(&&&&&connection.getInputStream()));&&&// 用来临时存储抓取到的每一行的数据&&&S&&&while ((line = in.readLine()) != null) {&&&&// 遍历抓取到的每一行并将其存储到result里面&&&&result +=&&&}&&} catch (Exception e) {&&&System.out.println("发送GET请求出现异常!" + e);&&&e.printStackTrace();&&}&&// 使用finally来关闭输入流&&finally {&&&try {&&&&if (in != null) {&&&&&in.close();&&&&}&&&} catch (Exception e2) {&&&&e2.printStackTrace();&&&}&&}&&&}&public static void main(String[] args) {&&// 定义即将访问的链接&&String url = "";&&// 访问链接并获取页面内容&&String result = sendGet(url);&&System.out.println(result);&}}
这样看起来稍微整洁了一点,请原谅我这个强迫症。
接下来的任务,就是从获取到的一大堆东西里面找到那个图片的链接。
我们首先可以想到的方法,是对页面源码的字符串result使用indexof函数进行String的子串搜索。
没错这个方法是可以慢慢解决这个问题,比如直接indexOf("src")找到开始的序号,然后再稀里哗啦的搞到结束的序号。
不过我们不能一直使用这种方法,毕竟草鞋只适合出门走走,后期还是需要切假腿来拿人头的。
请原谅我的乱入,继续。
那么我们用什么方式来寻找这张图片的src呢?
没错,正如下面观众所说,正则匹配。
如果有同学不太清楚正则,可以参照这篇文章:[Python]网络爬虫(七):Python中的正则表达式教程。
简单来说,正则就像是匹配。
比如三个胖子站在这里,分别穿着红衣服,蓝衣服,绿衣服。
正则就是:抓住那个穿绿衣服的!
然后把绿胖子单独抓了出来。
就是这么简单。
但是正则的语法却还是博大精深的,刚接触的时候难免有点摸不着头脑,
向大家推荐一个正则的在线测试工具:正则表达式在线测试。
有了正则这个神兵利器,那么怎么在java里面使用正则呢?
先来看个简单的小李子吧。
啊错了,小栗子。
&&// 定义一个样式模板,此中使用正则表达式,括号中是要抓的内容&&// 相当于埋好了陷阱匹配的地方就会掉下去&&Pattern pattern = pile("href=\"(.+?)\"");&&// 定义一个matcher用来做匹配&&Matcher matcher = pattern.matcher("<a href=\"index.html\">我的主页</a>");&&// 如果找到了&&if (matcher.find()) {&&&// 打印出结果&&&System.out.println(matcher.group(1));&&}
运行结果:
index.html
没错,这就是我们的第一个正则代码。
这样应用的抓取图片的链接想必也是信手拈来了。
我们将正则匹配封装成一个函数,然后将代码作如下修改:
import java.io.*;import java.net.*;import java.util.regex.*;public class Main {&static String SendGet(String url) {&&// 定义一个字符串用来存储网页内容&&String result = "";&&// 定义一个缓冲字符输入流&&BufferedReader in =&&try {&&&// 将string转成url对象&&&URL realUrl = new URL(url);&&&// 初始化一个链接到那个url的连接&&&URLConnection connection = realUrl.openConnection();&&&// 开始实际的连接&&&connection.connect();&&&// 初始化 BufferedReader输入流来读取URL的响应&&&in = new BufferedReader(new InputStreamReader(&&&&&connection.getInputStream()));&&&// 用来临时存储抓取到的每一行的数据&&&S&&&while ((line = in.readLine()) != null) {&&&&// 遍历抓取到的每一行并将其存储到result里面&&&&result +=&&&}&&} catch (Exception e) {&&&System.out.println("发送GET请求出现异常!" + e);&&&e.printStackTrace();&&}&&// 使用finally来关闭输入流&&finally {&&&try {&&&&if (in != null) {&&&&&in.close();&&&&}&&&} catch (Exception e2) {&&&&e2.printStackTrace();&&&}&&}&&&}&static String RegexString(String targetStr, String patternStr) {&&// 定义一个样式模板,此中使用正则表达式,括号中是要抓的内容&&// 相当于埋好了陷阱匹配的地方就会掉下去&&Pattern pattern = pile(patternStr);&&// 定义一个matcher用来做匹配&&Matcher matcher = pattern.matcher(targetStr);&&// 如果找到了&&if (matcher.find()) {&&&// 打印出结果&&&return matcher.group(1);&&}&&return "";&}&public static void main(String[] args) {&&// 定义即将访问的链接&&String url = "";&&// 访问链接并获取页面内容&&String result = SendGet(url);&&// 使用正则匹配图片的src内容&&String imgSrc = RegexString(result, "即将的正则语法");&&// 打印结果&&System.out.println(imgSrc);&}}
好的,现在万事俱备,只差一个正则语法了!
那么用什么正则语句比较合适呢?
我们发现只要抓住了src="xxxxxx"这个字符串,就能抓出整个src链接,
所以简单的正则语句:src=\"(.+?)\"
完整代码如下:
import java.io.*;import java.net.*;import java.util.regex.*;public class Main {&static String SendGet(String url) {&&// 定义一个字符串用来存储网页内容&&String result = "";&&// 定义一个缓冲字符输入流&&BufferedReader in =&&try {&&&// 将string转成url对象&&&URL realUrl = new URL(url);&&&// 初始化一个链接到那个url的连接&&&URLConnection connection = realUrl.openConnection();&&&// 开始实际的连接&&&connection.connect();&&&// 初始化 BufferedReader输入流来读取URL的响应&&&in = new BufferedReader(new InputStreamReader(&&&&&connection.getInputStream()));&&&// 用来临时存储抓取到的每一行的数据&&&S&&&while ((line = in.readLine()) != null) {&&&&// 遍历抓取到的每一行并将其存储到result里面&&&&result +=&&&}&&} catch (Exception e) {&&&System.out.println("发送GET请求出现异常!" + e);&&&e.printStackTrace();&&}&&// 使用finally来关闭输入流&&finally {&&&try {&&&&if (in != null) {&&&&&in.close();&&&&}&&&} catch (Exception e2) {&&&&e2.printStackTrace();&&&}&&}&&&}&static String RegexString(String targetStr, String patternStr) {&&// 定义一个样式模板,此中使用正则表达式,括号中是要抓的内容&&// 相当于埋好了陷阱匹配的地方就会掉下去&&Pattern pattern = pile(patternStr);&&// 定义一个matcher用来做匹配&&Matcher matcher = pattern.matcher(targetStr);&&// 如果找到了&&if (matcher.find()) {&&&// 打印出结果&&&return matcher.group(1);&&}&&return "Nothing";&}&public static void main(String[] args) {&&// 定义即将访问的链接&&String url = "";&&// 访问链接并获取页面内容&&String result = SendGet(url);&&// 使用正则匹配图片的src内容&&String imgSrc = RegexString(result, "src=\"(.+?)\"");&&// 打印结果&&System.out.println(imgSrc);&}}
这样我们就能用java抓出百度LOGO的链接了。
好吧虽然花了很多时间讲百度,但是基础要打扎实啦,下次我们正式开始抓知乎咯!~
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具7143人阅读
Python学习(5)
博客首发至
最近学习了一点网络爬虫,并实现了使用python来爬取知乎的一些功能,这里做一个小的总结。网络爬虫是指通过一定的规则自动的从网上抓取一些信息的程序或脚本。我们知道机器学习和数据挖掘等都是从大量的数据出发,找到一些有价值有规律的东西,而爬虫则可以帮助我们解决获取数据难的问题,因此网络爬虫是我们应该掌握的一个技巧。
python有很多开源工具包供我们使用,我这里使用了requests、BeautifulSoup4、json等包。requests模块帮助我们实现http请求,bs4模块和json模块帮助我们从获取到的数据中提取一些想要的信息,几个模块的具体功能这里不具体展开。下面我分功能来介绍如何爬取知乎。
要想实现对知乎的爬取,首先我们要实现模拟登录,因为不登录的话好多信息我们都无法访问。下面是登录函数,这里我直接使用了知乎用户的登录函数,具体如下。其中你要在函数中的data里填上你的登录账号和密码,然后在爬虫之前先执行这个函数,不出意外的话你就登录成功了,这时你就可以继续抓取想要 的数据。注意,在首次使用该函数时,程序会要求你手动输入captcha码,输入之后当前文件夹会多出cookiefile文件和zhihucaptcha.gif,前者保留了cookie信息,后者则保存了验证码,之后再去模拟登录时,程序会自动帮我们填上验证码。
def login():
loginURL = '/login/email'
headers = {
"User-Agent": 'Mozilla/5.0 (M Intel Mac OS X 10.10; rv:41.0) Gecko/ Firefox/41.0',
"Referer": "/",
'Host': '',
'email': '',
'password': '**************',
'rememberme': "true",
s = requests.session()
global xsrf
if os.path.exists('cookiefile'):
with open('cookiefile') as f:
cookie = json.load(f)
s.cookies.update(cookie)
req1 = s.get(url, headers=headers)
soup = BeautifulSoup(req1.text, "html.parser")
xsrf = soup.find('input', {'name': '_xsrf', 'type': 'hidden'}).get('value')
with open('zhihu.html', 'w') as f:
f.write(req1.content)
req = s.get(url, headers=headers)
soup = BeautifulSoup(req.text, "html.parser")
xsrf = soup.find('input', {'name': '_xsrf', 'type': 'hidden'}).get('value')
data['_xsrf'] = xsrf
timestamp = int(time.time() * 1000)
captchaURL = '/captcha.gif?=' + str(timestamp)
print captchaURL
with open('zhihucaptcha.gif', 'wb') as f:
captchaREQ = s.get(captchaURL, headers=headers)
f.write(captchaREQ.content)
loginCaptcha = raw_input('input captcha:\n').strip()
data['captcha'] = loginCaptcha
print data
loginREQ = s.post(loginURL, headers=headers, data=data)
if not loginREQ.json()['r']:
print s.cookies.get_dict()
with open('cookiefile', 'wb') as f:
json.dump(s.cookies.get_dict(), f)
print 'login fail'
需要注意的是,在login函数中有一个全局变量s=reequests.session(),我们用这个全局变量来访问知乎,整个爬取过程中,该对象都会保持我们的持续模拟登录。
获取用户基本信息
知乎上每个用户都有一个唯一ID,例如我的ID是marcovaldong,那么我们就可以通过访问地址
来访问我的主页。个人主页中包含了居住地、所在行业、性别、教育情况、获得的赞数、感谢数、关注了哪些人、被哪些人关注等信息。因此,我首先介绍如何通过爬虫来获取某一个知乎用户的一些信息。下面的函数get_userInfo(userID)实现了爬取一个知乎用户的个人信息,我们传递给该用户一个用户ID,该函数就会返回一个 list,其中包含昵称、ID、居住地、所在行业、性别、所在公司、职位、毕业学校、专业、赞同数、感谢数、提问数、回答数、文章数、收藏数、公共编辑数量、关注的人数、被关注的人数、主页被多少个人浏览过等19个数据。
def get_userInfo(userID):
user_url = '/people/' + userID
response = s.get(user_url, headers=header_info)
soup = BeautifulSoup(response.content, 'lxml')
name = soup.find_all('span', {'class': 'name'})[1].string
ID = userID
location = soup.find('span', {'class': 'location item'})
if location == None:
location = 'None'
location = location.string
business = soup.find('span', {'class': 'business item'})
if business == None:
business = 'None'
business = business.string
gender = soup.find('input', {'checked': 'checked'})
if gender == None:
gender = 'None'
gender = gender['class'][0]
employment = soup.find('span', {'class': 'employment item'})
if employment == None:
employment = 'None'
employment = employment.string
position = soup.find('span', {'class': 'position item'})
if position == None:
position = 'None'
position = position.string
education = soup.find('span', {'class': 'education item'})
if education == None:
education = 'None'
education = education.string
major = soup.find('span', {'class': 'education-extra item'})
if major == None:
major = 'None'
major = major.string
agree = int(soup.find('span', {'class': 'zm-profile-header-user-agree'}).strong.string)
thanks = int(soup.find('span', {'class': 'zm-profile-header-user-thanks'}).strong.string)
infolist = soup.find_all('a', {'class': 'item'})
asks = int(infolist[1].span.string)
answers = int(infolist[2].span.string)
posts = int(infolist[3].span.string)
collections = int(infolist[4].span.string)
logs = int(infolist[5].span.string)
followees = int(infolist[len(infolist)-2].strong.string)
followers = int(infolist[len(infolist)-1].strong.string)
scantime = int(soup.find_all('span', {'class': 'zg-gray-normal'})[len(soup.find_all('span', {'class': 'zg-gray-normal'}))-1].strong.string)
info = (name, ID, location, business, gender, employment, position,
education, major, agree, thanks, asks, answers, posts,
collections, logs, followees, followers, scantime)
return info
if __name__ == '__main__':
userID = 'marcovaldong'
info = get_userInfo(userID)
print 'The information of ' + userID + ' is: '
for i in range(len(info)):
print info[i]
下图是我的主页的部分截图,从上面可以看到这19个数据,下面第二张图是终端上显示的我的这19个数据,我们可以作个对照,看看是否全部抓取到了。这个函数我用了很长时间来调试,因为不同人的主页的信息完整程度是不同的,如果你在使用过程中发现了错误,欢迎告诉我。
获取某个答案的所有点赞者名单
知乎上有一个问题是,我参考了的这个答案,然后有了下面的这个函数。
这里先来大概的分析一下整个流程。我们要知道,知乎上的每一个问题都有一个唯一ID,这个可以从地址中看出来,例如问题的地址为
,其中就是其ID。而每一个问题下的每一个答案也有一个唯一ID,例如该问题下的最高票答案的地址链接为
,末尾的就是该答案在该问题下的唯一ID。不过我们这里用到的不是这两个ID,而是我们在抓取点赞者名单时的唯一ID,此ID的获得方法是这样:例如我们打算抓取的点赞者名单,首先打开firebug,点击“5321 人赞同”时,firebug会抓取到一个“GET voters_profile”的一个包,把光标放在上面,会看到一个链接
,其中的5430533才是我们在抓取点赞者名单时用到的一个唯一ID。注意此ID只有在答案被赞过后才有。(在这安利一下《人间正道是沧桑》这部电视剧,该剧以杨立青三兄妹的恩怨情仇为线索,从大革命时期到解放战争,比较全面客观的展现了国共两党之间的主义之争,每一次看都会新的认识和体会。)
在拿到唯一ID后,我们用requests模块去get到知乎返回的信息,其中有一个json语句,该json语句中包含点赞者的信息。另外,我们在网页上浏览点赞者名单时,一次只能看到20条,每次下拉到名单底部时又加载出20条信息,再加载20条信息时所用的请求地址也包含在前面的json语句中。因此我们需要从json语句中提取出点攒着信息和下一个请求地址。在网页上浏览点赞者名单时,我们可以看到点赞者的昵称、头像、获得了多少赞同和感谢,以及提问和回答的问题数量,这里我提取了每个点赞者的昵称、主页地址(也就是用户ID)、赞同数、感谢数、提问数和回答数。关于头像的提取,我会在下面的函数中实现。
在提取到点赞者名单后,我将者信息保存了以唯一ID命名的txt文件中。下面是函数的具体实现。
Zhihu = ''
def get_voters(ans_id):
file_name = str(ans_id) + '.txt'
f = open(file_name, 'w')
source_url = Zhihu + '/answer/' +str(ans_id) +'/voters_profile'
source = s.get(source_url, headers=header_info)
print source
content = source.content
print content
data = json.loads(content)
txt1 = '总赞数'
print txt1.decode('utf-8')
total = data['paging']['total']
print data['paging']['total']
nextsource_url = source_url
while nextsource_url!=Zhihu:
nextsource = s.get(nextsource_url, headers=header_info)
time.sleep(2)
nextsource = s.get(nextsource_url, headers=header_info)
nextcontent = nextsource.content
nextdata = json.loads(nextcontent)
for each in nextdata['payload']:
soup = BeautifulSoup(each, 'lxml')
tag = soup.a
title = tag['title']
href = '' + str(tag['href'])
list = soup.find_all('li')
votes = list[0].string
tks = list[1].string
ques = list[2].string
ans = list[3].string
string = title + '
' + href + '
' + votes + tks + ques + ans
f.write(string + '\n')
print string
txt3 = '有点赞者的信息缺失'
f.write(txt3.decode('utf-8') + '\n')
print txt3.decode('utf-8')
nextsource_url = Zhihu + nextdata['paging']['next']
注意,点赞者名单中会有匿名用户,或者有用户被注销,这时我们抓取不到此用户的信息,我这里在txt文件中添加了一句“有点赞者的信息缺失”。
使用同样的方法,我们就可以抓取到一个用户的关注者名单和被关注者名单,下面列出了这两个函数。但是关注者名单抓取函数有一个问题,每次使用其抓取大V的关注者名单时,当抓取到第10020个follower的时候程序就会报错,好像知乎有访问限制一般。这个问题,我还没有找到解决办法,希望有solution的告知一下。因为没有看到有用户关注10020+个人,因此抓取被关注者名单函数暂时未发现报错。
def get_followees(username):
followers_url = '/people/' + username + '/followees'
file_name = username + '.txt'
f = open(file_name, 'w')
data = s.get(followers_url, headers=header_info)
print data
content = data.content
soup = BeautifulSoup(content, "lxml")
totalsen = soup.select('span[class*="zm-profile-section-name"]')
total = int(str(totalsen[0]).split(' ')[4])
txt1 = '总的关注者人数:'
print txt1.decode('utf-8')
print total
follist = soup.select('div[class*="zm-profile-card"]')
for follower in follist:
tag =follower.a
title = tag['title']
href = '' + str(tag['href'])
%f' % (num, num / float(total))
Alist = follower.find_all('a', {'target': '_blank'})
votes = Alist[0].string
tks = Alist[1].string
ques = Alist[2].string
ans = Alist[3].string
string = title + '
' + href + '
' + votes + tks + ques + ans
print string.decode('utf-8')
print string.encode('gbk', 'ignore')
f.write(string + '\n')
n = total/20-1 if total/20.0-total/20 == 0 else total/20
for i in range(1, n+1, 1):
raw_hash_id = re.findall('hash_id(.*)', content)
hash_id = raw_hash_id[0][14:46]
_xsrf = xsrf
offset = 20*i
params = json.dumps({"offset": offset, "order_by": "created", "hash_id": hash_id})
payload = {"method":"next", "params": params, "_xsrf": _xsrf}
click_url = '/node/ProfileFolloweesListV2'
data = s.post(click_url, data=payload, headers=header_info)
source = json.loads(data.content)
for follower in source['msg']:
soup1 = BeautifulSoup(follower, 'lxml')
tag =soup1.a
title = tag['title']
href = '' + str(tag['href'])
%f' % (num, num/float(total))
Alist = soup1.find_all('a', {'target': '_blank'})
votes = Alist[0].string
tks = Alist[1].string
ques = Alist[2].string
ans = Alist[3].string
string = title + '
' + href + '
' + votes + tks + ques + ans
print string.decode('utf-8')
print string.encode('gbk', 'ignore')
f.write(string + '\n')
提取用户头像
再往下就是抓取用户头像了,给出某个唯一ID,下面的函数自动解析其主页,从中解析出该用户头像地址,抓取到图片并保存到本地文件,文件以用户唯一ID命名。
def get_avatar(userId):
url = '/people/' + userId
response = s.get(url, headers=header_info)
response = response.content
soup = BeautifulSoup(response, 'lxml')
name = soup.find_all('span', {'class': 'name'})[1].string
temp = soup.find('img', {'alt': name})
avatar_url = temp['src'][0:-6] + temp['src'][-4:]
filename = 'pics/' + userId + temp['src'][-4:]
f = open(filename, 'wb')
f.write(requests.get(avatar_url).content)
结合其他函数,我们就可以抓取到某个答案下所有点赞者的头像,某个大V所有followers的头像等。
抓取某个问题的所有答案
给出某个唯一ID,下面的函数帮助爬取到该问题下的所有答案。注意,答案内容只抓取文字部分,图片省略,答案保存在txt文件中,txt文件以答主ID命名。
def get_answer(questionID):
url = '/question/' + str(questionID)
data = s.get(url, headers=header_info)
soup = BeautifulSoup(data.content, 'lxml')
title = soup.title.string.split('\n')[2]
path = title
if not os.path.isdir(path):
os.mkdir(path)
description = soup.find('div', {'class': 'zm-editable-content'}).strings
file_name = path + '/description.txt'
fw = open(file_name, 'w')
for each in description:
each = each + '\n'
fw.write(each)
answer_num = int(soup.find('h3', {'id': 'zh-question-answer-num'}).string.split(' ')[0])
index = soup.find_all('div', {'tabindex': '-1'})
for i in range(len(index)):
print ('Scrapying the ' + str(num) + 'th answer......').encode('gbk', 'ignore')
a = index[i].find('a', {'class': 'author-link'})
title = str(num) + '__' + a.string
href = '' + a['href']
title = str(num) + '__匿名用户'
answer_file_name = path + '/' + title + '__.txt'
fr = open(answer_file_name, 'w')
answer_content = index[i].find('div', {'class': 'zm-editable-content clearfix'}).strings
answer_content = ['作者修改内容通过后,回答会重新显示。如果一周内未得到有效修改,回答会自动折叠。']
for content in answer_content:
fr.write(content + '\n')
_xsrf = xsrf
url_token = re.findall('url_token(.*)', data.content)[0][8:16]
n = answer_num/10-1 if answer_num/10.0-answer_num/10 == 0 else answer_num/10
for i in range(1, n+1, 1):
offset = 10*i
params = json.dumps({"url_token": url_token, "pagesize": 10, "offset": offset})
payload = {"method":"next", "params": params, "_xsrf": _xsrf}
click_url = '/node/QuestionAnswerListV2'
data = s.post(click_url, data=payload, headers=header_info)
data = json.loads(data.content)
for answer in data['msg']:
print ('Scrapying the ' + str(num) + 'th answer......').encode('gbk', 'ignore')
soup1 = BeautifulSoup(answer, 'lxml')
a = soup1.find('a', {'class': 'author-link'})
title = str(num) + '__' + a.string
href = '' + a['href']
title = str(num) + '__匿名用户'
answer_file_name = path + '/' + title + '__.txt'
fr = open(answer_file_name, 'w')
answer_content = soup1.find('div', {'class': 'zm-editable-content clearfix'}).strings
answer_content = ['作者修改内容通过后,回答会重新显示。如果一周内未得到有效修改,回答会自动折叠。']
for content in answer_content:
fr.write(content + '\n')
数据库存取数据
在完成了上面的这些功能后,下一步要做的是将用户信息保存在数据库中,方便数据的读取使用。我刚刚接触了一下sqlite3,仅仅实现了将用户信息存储在表格中。
def get_followeesInfo_toDB(userID):
conn = sqlite3.connect("Zhihu.db")
curs = conn.cursor()
curs.execute("create table if not exists userinfo(name TEXT, ID TEXT PRIMARY KEY, location TEXT, business TEXT, "
"gender TEXT, employment TEXT, position TEXT, education TEXT, major TEXT, "
"agree INTEGER, thanks INTEGER, asks INTEGER, answers INTEGER, posts INTEGER, "
"collections INTEGER, logs INTEGER, followees INTEGER, followers INTEGER, "
"scantime INTEGER)")
followees_url = '/people/' + userID + '/followees'
file_name = userID + '.txt'
f = open(file_name, 'w')
data = s.get(followees_url, headers=header_info)
print data
content = data.content
soup = BeautifulSoup(content, "lxml")
totalsen = soup.select('span[class*="zm-profile-section-name"]')
total = int(str(totalsen[0]).split(' ')[4])
txt1 = '总的关注者人数:'
print txt1.decode('utf-8')
print total
follist = soup.select('div[class*="zm-profile-card"]')
for follower in follist:
tag = follower.a
title = tag['title']
href = '' + str(tag['href'])
%f' % (num, num / float(total))
Alist = follower.find_all('a', {'target': '_blank'})
votes = Alist[0].string
tks = Alist[1].string
ques = Alist[2].string
ans = Alist[3].string
string = title + '
' + href + '
' + votes + tks + ques + ans
print string.decode('utf-8')
print string.encode('gbk', 'ignore')
f.write(string + '\n')
if title != '[已重置]':
print 'Analysising the data of this user...'
ID = href[28:]
curs.execute("insert or ignore into userinfo values (?, ?, ?, ?, ?, ?, ?, "
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", get_userInfo(ID))
print "This user account's state is abnormal..."
print 'This user account has been disabled...'
n = total / 20 - 1 if total / 20.0 - total / 20 == 0 else total / 20
for i in range(1, n + 1, 1):
raw_hash_id = re.findall('hash_id(.*)', content)
hash_id = raw_hash_id[0][14:46]
_xsrf = xsrf
offset = 20 * i
params = json.dumps({"offset": offset, "order_by": "created", "hash_id": hash_id})
payload = {"method": "next", "params": params, "_xsrf": _xsrf}
click_url = '/node/ProfileFolloweesListV2'
data = s.post(click_url, data=payload, headers=header_info)
source = json.loads(data.content)
for follower in source['msg']:
soup1 = BeautifulSoup(follower, 'lxml')
tag = soup1.a
title = tag['title']
href = '' + str(tag['href'])
%f' % (num, num / float(total))
Alist = soup1.find_all('a', {'target': '_blank'})
votes = Alist[0].string
tks = Alist[1].string
ques = Alist[2].string
ans = Alist[3].string
string = title + '
' + href + '
' + votes + tks + ques + ans
print string.decode('utf-8')
print string.encode('gbk', 'ignore')
f.write(string + '\n')
if title != '[已重置]':
print 'Analysising the data of this user...'
ID = href[28:]
curs.execute("insert or ignore into userinfo values (?, ?, ?, ?, ?, ?, ?, "
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", get_userInfo(ID))
print "This user account's state is abnormal..."
print 'This user account has been disabled...'
conn.close()
等熟悉了sqlite3的使用,我的下一步工作是抓取大量用户信息和用户之间的follow信息,尝试着将大V间的follow关系进行可视化。再下面的工作应该就是学习python的爬虫框架scrapy和爬取微博了。
另外,在写这篇博客的时候我又重新测试了一下上面的这些函数,然后我再在火狐上访问知乎时,系统提示“因为该账户过度频繁访问”而要求输入验证码,看来知乎已经开始限制爬虫了,这样以来我们就需要使用一些反反爬虫技巧了,比如控制访问频率等等,这个等以后有了系统的了解之后再作补充吧。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:143830次
积分:1824
积分:1824
排名:第19471名
原创:32篇
评论:17条
文章:10篇
阅读:38399
(1)(1)(2)(1)(8)(17)(1)(1)(5)(1)}

我要回帖

更多关于 如何学好c语言 知乎 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信