36kr爬虫,前瞻

  1 #!/usr/bin/env python  
  2 #-*- coding:utf-8 -*-  
  3 """ 
  4 @author:BanShaoHuan
  5 @file: first.py 
  6 @time: 2018/05/07
  7 @contact: banshaohuan@163.com
  8 @site:  
  9 @software: PyCharm 
 10 
 11 # code is far away from bugs with the god animal protecting
 12     I love animals. They taste delicious.
 13               ┏┓      ┏┓
 14             ┏┛┻━━━┛┻┓
 15             ┃      ☃      ┃
 16             ┃  ┳┛  ┗┳  ┃
 17             ┃      ┻      ┃
 18             ┗━┓      ┏━┛
 19                 ┃      ┗━━━┓
 20                 ┃  神兽保佑    ┣┓
 21                 ┃  永无BUG!   ┏┛
 22                 ┗┓┓┏━┳┓┏┛
 23                   ┃┫┫  ┃┫┫
 24                   ┗┻┛  ┗┻┛ 
 25 """
 26 
 27 import time
 28 import json
 29 import requests
 30 import re
 31 
 32 def get_html_encode(content_type, page_raw):
 33     '''
 34     :param content_type:str, response header的参数 一般有编码方式
 35     :param page_raw: str, html源码信息,里面的meta里面一般有编码方式
 36     :return:返回编码方式
 37     '''
 38     encode_list = re.findall(
 39         r'charset=([0-9a-zA-Z_-]+)', content_type, re.I
 40     )
 41     if encode_list:
 42         return encode_list[0]
 43     encode_list = re.findall(
 44         r'<meta.+charset=[\'"]*([0-9a-zA-Z_-]+)', page_raw, re.I
 45     )
 46     if encode_list:
 47         return encode_list[0]
 48 
 49 def _get_craw(url, headers, get_payload):
 50     '''
 51     :param url:str,Request URL
 52     :param headers: dict,Request Headers
 53     :param get_payload: dict,Query String Parameters
 54     :return:
 55     '''
 56     r = requests.get(url, headers=headers, params=get_payload)
 57     if r.status_code != 200:
 58         raise Exception(r.status_code)
 59     content_type = r.headers['Content-Type']
 60     if 'text/html' in content_type:
 61         encoding = get_html_encode(content_type, r.text)
 62         if encoding:
 63             r.encoding = encoding
 64         return r.text
 65     elif 'application/json' in content_type:
 66         return r.text
 67     elif 'application/pdf' in content_type:
 68         return r.content    # 返回字节
 69     elif 'image' in content_type:# 图片
 70         return r.content    # 返回字节
 71     else:
 72         return r.content
 73 
 74 def _post_craw(url, headers, get_payload):
 75     '''
 76     :param url:str,Request URL
 77     :param headers: dict,Request Headers
 78     :param get_payload: dict,Query String Parameters
 79     :return:
 80     '''
 81     r = requests.post(url, headers=headers, params=get_payload)
 82     if r.status_code != 200:
 83         raise Exception(r.status_code)
 84     content_type = r.headers['Content-Type']
 85     if 'text/html' in content_type:
 86         encoding = get_html_encode(content_type, r.text)
 87         if encoding:
 88             r.encoding = encoding
 89         return r.text
 90     elif 'application/json' in content_type:
 91         return r.text
 92     elif 'application/pdf' in content_type:
 93         return r.content    # 返回字节
 94     elif 'image' in content_type:# 图片
 95         return r.content    # 返回字节
 96     else:
 97         return r.content
 98 
 99 def _craw(method, url, headers=None, payload=None):
100     try:
101         if method == 'get':
102             return _get_craw(url, headers, payload)
103         elif method == 'post':
104             return _post_craw(url, headers, payload)
105         else:
106             raise Exception('method is wrong')
107     except Exception as e:
108         print(url)
109         print(e)
110 
111 def _json(data):
112     # 解析json
113     data = json.loads(data)
114     articles = data['data']['items']
115     print('文章id', '文章封面图片链接', '文章标题')
116     for article in articles:
117         print(article['id'], article['cover'], article['title'])
118 
119 def _image(data):
120     # 抓取图片
121     data = json.loads(data)
122     articles = data['data']['items']
123     for article in articles:
124         cover_url = article['cover']
125         article_id = article['id']
126         image_bytes = _craw('get', cover_url)
127         with open('img/{}.jpg'.format(article_id), 'wb') as f:
128             # 将字节写入文件,文件需要二进制形式
129             f.write(image_bytes)
130 
131 if __name__ == '__main__':
132     url = 'http://36kr.com/api/search-column/mainsite'
133     get_payload = {
134         'per_page':20,
135         'page':1,
136         '_':str(int(time.time() * 1000))
137     }
138     headers = {
139         'Host':'36kr.com',
140         'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
141     }
142     data = _craw('get', url, headers, get_payload)
143     # _json(data)
144     # _image(data)
145     # 抓取详情页
146     data = json.loads(data)
147     articles = data['data']['items']
148     for article in articles:
149         url = 'http://36kr.com/p/{}.html'.format(article['id'])
150         print(url)
151         html = _craw('get', url, headers)
152         print(html)

使用xpath进行爬虫前的小知识点,包括通过chrome对网页的抓包,判断网址的类型进行不同的操作

查看开发者工具network里面的信息,里面的信息比较多,因为html页面刚开始一般会加载js和css文件,我们不去管这些。我们抓取的是文本信息,所有我们一般查看type类型为docment和xhr的。docment类型一般的返回结果是html源码,xhr请求的返回结果一般是json格式。

鼠标往下滚动,触发翻页,有一个xhr请求,返回的结果,即是我们需要的文章列表页面的数据

可以看到有4部分:
(1)General一般包括请求的url,请求方法(get或者post),http请求服务器返回的状态码,200说明请求成功。
(2)Response Headers 是服务器返回的headers信息,一般会向浏览器设置cookie信息什么的,这里我们先不管。
(3)Request Headers 这一部分对于我们爬虫比较重要,是浏览器向服务器请求头信息,包括了浏览器当前状态的信息。一般我们要注意Cookie, Host, Referer, User-Agent等信息。
(4)Query String Parameters 请求参数,get方法请求即是url的问号后面那些东西,post方法是一些表单数据或者一些敏感信息,post方法参数在传输过程中会加密,所以post方法请求,保密性比较好。
 
到这里这个页面的抓包分析结束,Chrome抓包分析就是要找到我们所需要的数据是哪条请求链接,以及这个请求链接的Request Headers的参数和Query String Parameters参数。
从第一部分抓包分析可知:
(1)url为http://36kr.com/api/search-column/mainsite
(2)请求方法为get
(3)请求参数为per_page=20&page=2&_=1523873453996,从参数可知per_page=20是每页展示20篇文章,page=2为第2页,_=1523873453996即 _ 这个参数是请求当前时间点的时间戳
(4)headers当中的参数,一般比较重要的是:User-Agent, Referer, Host, Cookie等。如果遇到反爬,首先我们检查的就是headers,在可以获取到数据的情况下,headers里面的参数可以尽量少,获取不到的情况,就多添加一些,直到能够获取到数据。
 
posted @ 2018-05-07 16:51  banshaohuan  阅读(380)  评论(0)    收藏  举报