自学Python之四 爬虫底子知识储备,python爬虫

然后才能做第二步的数据请求(下方的截图对应网页上的不同区域的请求报文头和返回数据),发现知网的查询是分成两步的,必须要拿到xrsf,通过对知乎登陆是的抓包,Python爬虫学习系列教程 ,归根到底就是我们通过程序访问网站得到html代码

                                                                       
图二. 对应差异年份的笔录条数重返结果

网易已经变为了爬虫的球馆,本文利用Python中的requests库,模拟登录乐乎,获取cookie,保存到地面,然后那几个cookie作为登录的凭证,登入天涯论坛的主页面,爬取果壳网主页面上的难题和呼应难题回答的摘要。

有关果壳网验证码登录的题目,用到了Python上一位命关天的图样管理库PIL,若是那多少个,就把图片存到本地,手动输入。

自学Python之四 爬虫功底知识储备,python爬虫

  首先,推荐七个关于python爬虫不错的博客:Python爬虫入门教程专栏   和
Python爬虫学习体系教程 。写的都相当不错,笔者学习到了好多东西!在那,小编就自个儿看齐的学到的张开总括一下!

  爬虫正是叁个不息的去抓去网页的次第,依照大家的内需获得我们想要的结果!但大家又要让服务器感到是大家人在经过浏览器浏览不是程序所为!追根究底就是我们经进程序访谈网址拿到html代码,然后剖判html代码获取低价内容的进程。下边让咱们从最简单易行的爬虫起首:

  爬取一个页面源代码

  在python中,抓取网页的库是urllib2。下边看三个最简便易行的例证:

1 import urllib2
2 response = urllib2.urlopen('http://www.baidu.com/')
3 html = response.read()
4 print html

  试行到位后您会发觉窗口中打出了一群代码,其实正是百度主页的html代码!(抵制百度!!!)

  大家来看一下urlopen的用法:

1 >>> help(urllib2.urlopen)
2 Help on function urlopen in module urllib2:
3 
4 urlopen(url, data=None, timeout=<object object>, cafile=None, capath=None, cadefault=False, context=None)

  第八个参数为url,第一个为要发送的数据,第2个是逾期时间。其他的大家平时不用,就不表明了!第二五个参数不是必需的,因为皆有私下认可值,data默许值为None,timeout私下认可值为socket._GLOBAL_DEFAUTL_TIMEOUT。传入url之后,大家得到一个response对象,再次来到的音信就在此其间!通过response.read(卡塔尔(قطر‎获取里面包车型地铁原委。相通的大家得以组织二个Request类,作为参数字传送入urlopen中,那一个Request类中就包罗url,data,timeout等剧情。上边的代码我们能够写成那样:

1 import urllib2
2 
3 request = urllib2.Request("http://www.baidu.com")
4 response = urllib2.urlopen(request)
5 print response.read()

  那样是还是不是很清晰明了了?在构建Request的时候我们不可胜举会步向过多剧情,大家发出三个呼吁,服务器给我们一个响应。三个简便的爬虫就那样起飞了!

  POST和GET数据传送

  常常我们在浏览网页的时候难免涉及到登入注册,填写表单,大概跳转到某些页面,那时大家要跟服务器实行交互作用,向服务器发送数据,发送数据的不二秘技呢正是Post和Get,两个的分别在于GET格局直接以链接的花样拜谒,链接中蕴藏全数的参数,如:
 此中result=true正是Get传递的多寡,POST也正是Get就安全多了,它不会在链接上显得全数参数。

  Post方式:

 1 import urllib
 2 import urllib2
 3 
 4 values = {}
 5 values['username'] = "[email protected]"
 6 values['password'] = "******"
 7 data = urllib.urlencode(values) 
 8 url = "http://www.xxx.com/login?from=http://xxx/loginInfo"
 9 request = urllib2.Request(url,data)
10 response = urllib2.urlopen(request)
11 print response.read()

  在地点的代码中,大家成立了一个字典values,设置了username和password的值,然后通过urlencode函数将字典实行转码,命名字为data,然后用url和data实例化了三个Request类,传递给urlopen(卡塔尔(قطر‎。

  Get方式:

 1 import urllib
 2 import urllib2
 3 
 4 values={}
 5 values['username'] = "[email protected]"
 6 values['password']="******"
 7 data = urllib.urlencode(values) 
 8 url = "http://www.xxx.com/login"
 9 geturl = url + "?"+data
10 request = urllib2.Request(geturl)
11 response = urllib2.urlopen(request)
12 print response.read()

  在地点的代码中,大家创设了贰个字典values,设置了username和password的值,然后通过urlencode函数将字典实行转码,命名字为data,然后大家把data拼接在了url中,我们会得到如此的url:

  在完毕二个爬虫的时候,大家要依据供给,接纳post可能get情势开展访谈!可是除了上边那么些还相当不足,以往网址为了防止爬虫去访谈会进行部分检查实验,若是检查实验不经过就不会响应你的恳求,为了完全模拟浏览器专门的学业,大家往往要设置有个别headers属性,以致防盗链:

1 headers = { 'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  ,
2                         'Referer':'http://www.zhihu.com/articles' }  

3 request = urllib2.Request(url, data, headers)#利用data headers构造Request对象

  有个别网址恐怕会测验ip等,大家恐怕会用到urllib2的代办,有个别网址响应过慢大家得以设置其timeout。在拜谒网址的动静下大家恐怕会遇见有的网址破绽百出,大家要在前后相继中开展拍卖(长久以来的try…
except…得到错误音信内容卡塔尔(英语:State of Qatar):

 1 import urllib2
 2 
 3 req = urllib2.Request('http://www.xxx.com')
 4 try:
 5     urllib2.urlopen(req)
 6 except urllib2.URLError, e:
 7     if hasattr(e,"code"):
 8         print e.code
 9     if hasattr(e,"reason"):
10         print e.reason
11 else:
12     print "OK"

  经常见到的错误代码:400 违法央求  403 禁止访谈  404 未找到能源  500
服务器内部错误 200 访谈成功。

  在网页访谈进程中,不可制止的要用到cookies,我们的顺序要效仿浏览器的一举一动,在探访网页的时候不时要带上特定的cookies,那样才干学有所成访谈网页。关于cookies大家用到了cookielib,cookielib模块提供可存款和储蓄cookie的目的,以便于与urllib2合营使用举办网址访谈,利用内部的CookieJar类捕获和发送cookie,完结模拟登入,维持登陆意况等。

  获取cookie保存到变量:

 1 import urllib2
 2 import cookielib
 3 #声明一个CookieJar对象实例来保存cookie
 4 cookie = cookielib.CookieJar()
 5 #利用urllib2库的HTTPCookieProcessor对象来创建cookie处理器
 6 handler=urllib2.HTTPCookieProcessor(cookie)
 7 #通过handler来构建opener
 8 opener = urllib2.build_opener(handler)
 9 #此处的open方法同urllib2的urlopen方法,也可以传入request
10 response = opener.open('http://www.baidu.com')
11 for item in cookie:
12     print 'Name = '+item.name
13     print 'Value = '+item.value
14 #利用cookie请求访问另一个网址
15 gradeUrl = 'http://www.baidu.com/xxx/xx'
16 #请求访问
17 result = opener.open(gradeUrl)
18 print result.read()

  上边程序创设了贰个分包cookie的opener,在拜望登入url的时候,将登入后的cookie保存下去,然后利用这些cookie来访问其余的网站。

  上面放一个HttpClient.py,里面饱含了post和get方法,以至getcookies:

 1 import cookielib, urllib, urllib2, socket
 2 
 3 class HttpClient:
 4   __cookie = cookielib.CookieJar()
 5   __req = urllib2.build_opener(urllib2.HTTPCookieProcessor(__cookie))
 6   __req.addheaders = [
 7     ('Accept', 'application/javascript, */*;q=0.8'),
 8     ('User-Agent', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)')
 9   ]
10   urllib2.install_opener(__req)
11 
12   def Get(self, url, refer=None):
13     try:
14       req = urllib2.Request(url)
15       if not (refer is None):
16         req.add_header('Referer', refer)
17       return urllib2.urlopen(req, timeout=120).read()
18     except urllib2.HTTPError, e:
19       return e.read()
20     except socket.timeout, e:
21       return ''
22     except socket.error, e:
23       return ''
24 
25   def Post(self, url, data, refer=None):
26     try:
27       req = urllib2.Request(url, urllib.urlencode(data))
28       if not (refer is None):
29         req.add_header('Referer', refer)
30       return urllib2.urlopen(req, timeout=120).read()
31     except urllib2.HTTPError, e:
32       return e.read()
33     except socket.timeout, e:
34       return ''
35     except socket.error, e:
36       return ''
37 
38   def Download(self, url, file):
39     output = open(file, 'wb')
40     output.write(urllib2.urlopen(url).read())
41     output.close()
42 
43   def getCookie(self, key):
44     for c in self.__cookie:
45       if c.name == key:
46         return c.value
47     return ''
48 
49   def setCookie(self, key, val, domain):
50     ck = cookielib.Cookie(version=0, name=key, value=val, port=None, port_specified=False, domain=domain, domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)
51     self.__cookie.set_cookie(ck)

  

 

爬虫底子知识储备,python爬虫
首先,推荐五个有关python爬虫不错的博客:Python爬虫入门教程专栏 和
Python爬虫学习种类教程。…

在成功了数额级为生机勃勃的等第后,就开头筹算大面积地获取数据了,那时就要思量功效以致防范网站踢人了。

爬取微博的严重性的有的:模拟登录

经过对搜狐登入是的抓包,能够开采登录今日头条,须要post多个参数,二个是账号,八个是密码,多个是xrsf。
本条xrsf遮掩在表单里面,每一趟登录的时候,应该是服务器随机发生三个字符串。全部,要效仿登入的时候,必须要拿到xrsf。

用chrome (大概火狐 httpfox 抓包解析)的结果:

image.png

故此,应当要获得xsrf的数值,注意那是一个动态变化的参数,每回都不平等。

image.png

注意findall和find_all函数的区分。

获得xsrf,下边就能够效仿登录了。
行使requests库的session对象,创立三个会话的补益是,能够把同三个顾客的两样乞求联系起来,直到会话甘休都会自行管理cookies。

image.png

瞩目:cookies
是当前目录的多个文书,那几个文件保留了今日头条的cookie,要是是第2个登入,那么自然是绝非这些文件的,不可能通过cookie文件来登入。一定要输入密码。

def login(secret, account):
    # 通过输入的用户名判断是否是手机号
    if re.match(r"^1\d{10}$", account):
        print("手机号登录 \n")
        post_url = 'https://www.zhihu.com/login/phone_num'
        postdata = {
            '_xsrf': get_xsrf(),
            'password': secret,
            'remember_me': 'true',
            'phone_num': account,
        }
    else:
        if "@" in account:
            print("邮箱登录 \n")
        else:
            print("你的账号输入有问题,请重新登录")
            return 0
        post_url = 'https://www.zhihu.com/login/email'
        postdata = {
            '_xsrf': get_xsrf(),
            'password': secret,
            'remember_me': 'true',
            'email': account,
        }
    try:
        # 不需要验证码直接登录成功
        login_page = session.post(post_url, data=postdata, headers=headers)
        login_code = login_page.text
        print(login_page.status_code)
        print(login_code)
    except:
        # 需要输入验证码后才能登录成功
        postdata["captcha"] = get_captcha()
        login_page = session.post(post_url, data=postdata, headers=headers)
        login_code = eval(login_page.text)
        print(login_code['msg'])
    session.cookies.save()
try:
    input = raw_input
except:
    pass

那是登入的函数,通过login函数来登入,post 本人的账号,密码和xrsf
到新浪登入认证的页面上去,然后拿走cookie,将cookie保存到当前目录下的文件之中。下一次登入的时候,直接读取那几个cookie文件。

#LWP-Cookies-2.0
Set-Cookie3: cap_id="\"YWJkNTkxYzhiMGYwNDU2OGI4NDUxN2FlNzBmY2NlMTY=|1487052577|4aacd7a27b11a852e637262bb251d79c6cf4c8dc\""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:37Z"; version=0
Set-Cookie3: l_cap_id="\"OGFmYTk3ZDA3YmJmNDQ4YThiNjFlZjU3NzQ5NjZjMTA=|1487052577|0f66a8f8d485bc85e500a121587780c7c8766faf\""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:37Z"; version=0
Set-Cookie3: login="\"NmYxMmU0NWJmN2JlNDY2NGFhYzZiYWIxMzE5ZTZiMzU=|1487052597|a57652ef6e0bbbc9c4df0a8a0a59b559d4e20456\""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:57Z"; version=0
Set-Cookie3: q_c1="ee29042649aa4f87969ed193acb6cb83|1487052577000|1487052577000"; path="/"; domain=".zhihu.com"; path_spec; expires="2020-02-14 06:09:37Z"; version=0
Set-Cookie3: z_c0="\"QUFCQTFCOGdBQUFYQUFBQVlRSlZUVFVzeWxoZzlNbTYtNkt0Qk1NV0JLUHZBV0N6NlNNQmZ3PT0=|1487052597|dcf272463c56dd6578d89e3ba543d46b44a22f68\""; path="/"; domain=".zhihu.com"; path_spec; expires="2017-03-16 06:09:57Z"; httponly=None; version=0

那是cookie文件的剧情

以下是源码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
try:
    import cookielib
except:
    import http.cookiejar as cookielib
import re
import time
import os.path
try:
    from PIL import Image
except:
    pass

from bs4 import BeautifulSoup


# 构造 Request headers
agent = 'Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0'
headers = {
    "Host": "www.zhihu.com",
    "Referer": "https://www.zhihu.com/",
    'User-Agent': agent
}

# 使用登录cookie信息
session = requests.session()
session.cookies = cookielib.LWPCookieJar(filename='cookies')
try:
    session.cookies.load(ignore_discard=True)
except:
    print("Cookie 未能加载")



def get_xsrf():
    '''_xsrf 是一个动态变化的参数'''
    index_url = 'https://www.zhihu.com'
    # 获取登录时需要用到的_xsrf
    index_page = session.get(index_url, headers=headers)
    html = index_page.text
    pattern = r'name="_xsrf" value="(.*?)"'
    # 这里的_xsrf 返回的是一个list
    _xsrf = re.findall(pattern, html)
    return _xsrf[0]





# 获取验证码
def get_captcha():
    t = str(int(time.time() * 1000))
    captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
    r = session.get(captcha_url, headers=headers)
    with open('captcha.jpg', 'wb') as f:
        f.write(r.content)
        f.close()
    # 用pillow 的 Image 显示验证码
    # 如果没有安装 pillow 到源代码所在的目录去找到验证码然后手动输入
    try:
        im = Image.open('captcha.jpg')
        im.show()
        im.close()
    except:
        print(u'请到 %s 目录找到captcha.jpg 手动输入' % os.path.abspath('captcha.jpg'))
    captcha = input("please input the captcha\n>")
    return captcha





def isLogin():
    # 通过查看用户个人信息来判断是否已经登录
    url = "https://www.zhihu.com/settings/profile"
    login_code = session.get(url, headers=headers, allow_redirects=False).status_code
    if login_code == 200:
        return True
    else:
        return False


def login(secret, account):
    # 通过输入的用户名判断是否是手机号
    if re.match(r"^1\d{10}$", account):
        print("手机号登录 \n")
        post_url = 'https://www.zhihu.com/login/phone_num'
        postdata = {
            '_xsrf': get_xsrf(),
            'password': secret,
            'remember_me': 'true',
            'phone_num': account,
        }
    else:
        if "@" in account:
            print("邮箱登录 \n")
        else:
            print("你的账号输入有问题,请重新登录")
            return 0
        post_url = 'https://www.zhihu.com/login/email'
        postdata = {
            '_xsrf': get_xsrf(),
            'password': secret,
            'remember_me': 'true',
            'email': account,
        }
    try:
        # 不需要验证码直接登录成功
        login_page = session.post(post_url, data=postdata, headers=headers)
        login_code = login_page.text
        print(login_page.status_code)
        print(login_code)
    except:
        # 需要输入验证码后才能登录成功
        postdata["captcha"] = get_captcha()
        login_page = session.post(post_url, data=postdata, headers=headers)
        login_code = eval(login_page.text)
        print(login_code['msg'])
    session.cookies.save()
try:
    input = raw_input
except:
    pass



## 將main的問題列表輸出在shell上面
def  getPageQuestion(url2):  
  mainpage = session.get(url2, headers=headers)
  soup=BeautifulSoup(mainpage.text,'html.parser')
  tags=soup.find_all("a",class_="question_link")
  #print tags

  for tag in tags:
    print tag.string

# 將main頁面上面的問題的回答的摘要輸出在shell上面
def getPageAnswerAbstract(url2):
    mainpage=session.get(url2,headers=headers)
    soup=BeautifulSoup(mainpage.text,'html.parser')
    tags=soup.find_all('div',class_='zh-summary summary clearfix')

    for tag in tags:
       # print tag
        print tag.get_text()
        print '詳細內容的鏈接 : ',tag.find('a').get('href')


def getPageALL(url2):
    #mainpage=session.get(url2,headers=headers)
    #soup=BeautifulSoup(mainpage.text,'html.parser')
    #tags=soup.find_all('div',class_='feed-item-inner')
    #print "def getpageall "
    mainpage=session.get(url2,headers=headers)
    soup=BeautifulSoup(mainpage.text,'html.parser')
    tags=soup.find_all('div',class_='feed-content')
    for tag in tags:
        #print tag
        print tag.find('a',class_='question_link').get_text()
        # 這裏有一點問題 bs 還是用的不是太熟練
        #print tag.find('a',class_='zh-summary summary clearfix').get_text()
        #print tag.find('div',class_='zh-summary summary clearfix').get_text()


if __name__ == '__main__':
    if isLogin():
        print('您已经登录')
        url2='https://www.zhihu.com'
        # getPageQuestion(url2)
        #getPageAnswerAbstract(url2)
        getPageALL(url2)
    else:
        account = input('请输入你的用户名\n>  ')
        secret = input("请输入你的密码\n>  ")
        login(secret, account)

运作结果:

image.png

总的说来,就是对此某个懂web的爬虫小白,最佳就是还原网址原来的乞请,那样基本上诉求数据就不会有太大难点了。

git链接:

https://github.com/zhaozhengcoder/Spider/tree/master/spider\_zhihu

近来在练习写爬虫的时候,刚巧同学的女对象有要求,大致是爬取知网内的几千个大旨的数额,每叁个宗旨的条数记录有几条的到几千条的不等,总来的来讲也终归个上万数码级的爬虫了,剖析了下知网,开掘接收正规检索,能够做到自身的对象,然后通过chrome的developer
tools大致解析了下了诉求数据包,发掘知网的询问是分成两步的,第一步是贰个总的央浼(查询的尺度基本上都在率先步里面了),会回到贰个串

PPS:笔者所驾驭的爬虫与反爬虫战略

反爬虫最中央的政策:

  1. 检查浏览器http哀告里面包车型客车user-agent字段
  2. 检查http要求的referer(即当前的那么些页面是从哪个页面跳转过来的)

爬虫战略:
那八个都以在http左券的报文段的检讨,相像爬虫端能够很平价的设置这一个字段的值,来瞒上欺下服务器。

反爬虫进级战术:
1.像今日头条相似,在签到的表单里面放入一个隐蔽字段,里面会有八个即兴数,每一趟都差异等,那样除非你的爬虫脚本可以分析这一个自由数,不然下次爬的时候就非常了。
2.笔录探访的ip,总括访谈次数,如果次数太高,能够以为这些ip不通常。

爬虫晋级计策:
1.像那篇随笔提到的,爬虫也能够先深入分析一下掩瞒字段的值,然后再举办效仿登入。
2.爬虫能够应用ip代理池的办法,来幸免被发觉。同不时间,也得以爬一会小憩一会的主意来下滑功效。别的,服务器依照ip访谈次数来开展反爬,再ipv6未有周到推广的时代,这几个计谋会非常轻易引致风险。(那个是本身个人的知道)。

反爬虫进进级战略:
1.数量投毒,服务器在团结的页面上放置比超多遮盖的url,那些url存在于html文件文件之中,然而通过css恐怕js使她们不会被出示在客商观看的页面上面。(确定保障顾客点击不到)。那么,爬虫在爬取网页的时候,很用可能取访问那几个url,服务器能够100%的感到那是爬虫干的,然后能够重回给她某些荒谬的数量,或许是不容响应。

爬虫进进级计策:
1.种种网址即便供给反爬虫,可是无法把百度,谷歌(Google卡塔尔如此的查究引擎的爬虫给干了(干了的话,你的网址在百度都在说搜不到!)。那样爬虫应该就足以杜撰是百度的爬虫去爬。(不过ip可能恐怕被查出,因为您的ip并非百度的ip)

反爬虫进进进级计谋:
给个验证码,让您输入现在本事登入,登陆之后,手艺访问。

爬虫进进进级攻略:
图像识别,机器学习,识别验证码。但是那一个应该相比难,恐怕说花费相比较高。

参谋资料:
廖雪峰的python教程
静觅的python教程
requests库官方文书档案
segmentfault下面有一个人的关于腾讯网爬虫的博客,找不到链接了

至于缘何要分成两步,每三个区域对应三个两样的央求,那么些都以网址本人的规划,笔者也没做过web开辟,这么做有啥亮点我的确不知底/擦汗,作者的要害就是仿照它在网页上的伸手,达成批量化的多寡得到。