平时使用简书搜索内容的时候总感觉用着不怎么顺手,搜索出的内容乘次不齐,我自己比较倾向于去看点赞数量多的文章,这样的文章一般质量还可以,于是乎想用python来写一个用自己的规则来搜索内容的爬虫。
一、明确自己方向
打开简书网站,输入搜索内容搜索。右键检查元素(safari浏览器中),查看网页源码。一开始想,搜索出的文章标题和链接都在源码中,但是前前后后找了一下,没找到,问了两三个学过python的同学,他们也不清楚(我也是醉了0.0)。
1CA648E4-6DFB-47B0-A792-FEAD770F178F.png
在折腾了一下后自己打开抓包工具,看看搜索的时候会不会有与服务器的数据请求。果不其然,搜索的内容是通过http请求得到的。
63C52DC4-D6D5-4429-9424-05A6F82BB483.png
从上面的图片可以看出,返回的数据中包含了文章的标题,链接、作者、喜欢数量、搜索结果的总页数、搜索结果总数量,这些都是我想获取到,也是要用到的。
二、着手获取数据
然后自己构造一个http请求去获取数据。设置请求的链接、设置请求的header。这里我们是模拟浏览器来请求的,所以用到抓包获得的浏览器请求的时候的headers就可以了,全部复制下来,设置到请求的headers中。如果不是模拟浏览器来请求,请求会出错,获取不到内容,因为这是简书的反爬虫措施之一。
9C12AD91-A116-4EF1-9602-50BE880F5633.png
1.设置header:
headers = {
# '(Request - Line)' : 'POST / search / do?q = ios & type = note & page = 1 & order_by = default HTTP / 1.1',
'Host': 'www.jianshu.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:49.0) Gecko/20100101 Firefox/49.0',
'Accept': 'application/json',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'X-CSRF-Token': 'AaptezFCpyFRqRuLfUNSec2sXezPdSkevhSOumWdjmQBwcsqtFj7Y4++9C7q1KNYcdDeKYPYSx2LF8TOv/yraw==',
'Referer': 'http://www.jianshu.com/search?q=ios&page=' + str(
self.currentPageCount) + '&type=note',
'Cookie': '_ga=GA1.2.1123264411.1477987596; _m7e_session=ca00c4a06553d05d9582f8608cec77d6; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2215f90ad001a20-0dec543cc50fda-485960-1024000-15f90ad001b249%22%2C%22%24device_id%22%3A%2215f90ad001a20-0dec543cc50fda-485960-1024000-15f90ad001b249%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D; sajssdk_2015_cross_new_user=1; Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1509960778,1509981445; _gid=GA1.2.809709895.1509960780; signin_redirect=http%3A%2F%2Fwww.jianshu.com%2Fsearch%3Fq%3Dios%26page%3D1%26type%3Dnote; Hm_lpvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1509982101'
}
2.设置请求的参数:
2EEFDCDB-392C-4143-B7D6-13A8F21D3080.png
这里我们看到有四个参数 q:搜索内容 type:搜索类型,这里我们就填note就可以了 page:页数 order_by:排序的顺序
因为返回的搜索是分页的,而我要遍历所有的分页去筛选内容,所以我要在设置请求的时候,要动态的去设置请求的页数。
url = 'http://www.jianshu.com/search/do?q=' + 搜索内容 + '&type=note&page=' + str(
页数) + '&order_by=default'
3.请求并解析数据
47B0B090-7EED-4D16-8C64-13CFB39BC3B2.png
通过观察返回的json数据,我们可以看到,搜索出的结果、总页数、每页的数据条数、搜索出的文章。
文章的总页数:total_pages
文章列表:entries
文章的数据结构:
标题:title
内容:content
有效url的一部分: slug (会在拼接文章链接的时候用到)
喜欢数:likes_count
匹配标题:
dr = re.compile(r'<[^>]+>', re.S)
airtcleTile = dr.sub('', airtcleTile)
4.请求错误处理:
当我们不断去请求的时候会报请求过于频繁的错误,这里我们需要等个一两秒再去请求。这样就能不断的请求数据了。
elif (json_data.has_key('error')):
print json_data['error']
self.sleepCount += 1
time.sleep(self.sleepCount)
self.getUrl()
三、运行程序,静静等待获取的内容
运行程序结果
抓包数据
源码在这里,稍后我会继续增加功能。
#-*- coding: utf-8 -*-
import re
import urllib2
import json
import requests
import time
class JianShuSearch:
def __init__(self):
self.total_pages = 1
self.userlink = []
self.neadAirtcles = []
self.currentPageCount = 1
self.searchContent = ' '
self.sleepCount = 2
def getUrl(self):
# while len(userlink) == 0:
if (self.searchContent == ' '):
self.searchContent = raw_input('请输入想检索的内容: ')
url = 'https://www.jianshu.com/search/do?q=' + self.searchContent + '&type=note&page=' + str(
self.currentPageCount) + '&order_by=default'
headers = {
# '(Request - Line)' : 'POST / search / do?q = ios & type = note & page = 1 & order_by = default HTTP / 1.1',
'Host': 'www.jianshu.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:49.0) Gecko/20100101 Firefox/49.0',
'Accept': 'application/json',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'X-CSRF-Token': 'irU6/gcVeIjgX7alknOXf+jV5Ubi6FbsXlAB0cT5YWIyT4zbV7BNWg+180IAqX/DIQaDkVClfaB00M86dLfUNw==',
'Referer': 'https://www.jianshu.com/search?q=ios&page=' + str(
self.currentPageCount) + '&type=note',
'Cookie': '_ga=GA1.2.1123264411.1477987596; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2215f90ad001a20-0dec543cc50fda-485960-1024000-15f90ad001b249%22%2C%22%24device_id%22%3A%2215f90ad001a20-0dec543cc50fda-485960-1024000-15f90ad001b249%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D; Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1516764054; signin_redirect=https%3A%2F%2Fwww.jianshu.com%2Fsearch%3Futf8%3D%25E2%259C%2593%26q%3Dios; read_mode=day; default_font=font2; locale=zh-CN; _m7e_session=91e8f3ffb07619741a2be2821dde9f17; Hm_lpvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1516764082'
}
page = requests.post(url=url, headers=headers) # 获取网页中的json文件。
json_data = json.loads(page.text)
if (self.currentPageCount == 1):
self.total_pages = json_data['total_pages']
if (self.total_pages > 0 and json_data.has_key('entries')):
for airtcle in json_data['entries']:
# 标题
airtcleTile = airtcle['title']
dr = re.compile(r'<[^>]+>', re.S)
airtcleTile = dr.sub('', airtcleTile)
# 链接
slug = airtcle['slug']
airtcleUrl = 'http://www.jianshu.com/p/' + slug
likeCount = airtcle['likes_count']
if (likeCount > 10):
self.neadAirtcles.append(airtcle)
titleAdnUrl = airtcleTile + ' ' + airtcleUrl + ' like: ' + str(likeCount)
print titleAdnUrl
self.currentPageCount += 1
if (self.currentPageCount < self.total_pages):
time.sleep(self.sleepCount)
self.getUrl()
elif (json_data.has_key('error')):
print json_data['error']
self.sleepCount += 1
time.sleep(self.sleepCount)
self.getUrl()
jianshuSearch = JianShuSearch()
jianshuSearch.getUrl()