爬虫入门(一)

 Von's Blog     2019-10-17   5266 words    & views

requests库的相关用法

GET与POST

经典用法:

import requests
r = requests.get('https://www.baidu.com')

如果我们想要添加相应的参数,我们可以使用params这个参数。

import requests
data = {'name':'linhong','age':'20'}
r = requests.get('http://httpbin.org/get',params = data)

添加headers

import requests
headrs = {'User-Agent':'Mozilla/5.0'}
r = requests.get('https://www.zhihu.com/explore',headers=headers)

POST请求的实现和GET请求的实现十分类似

import requests
data = {'name':'sushuo','age':'21'}
r = requests.post('http://httpbin.org/post',data=data)

响应

常用的有以下几种相应类型

import requests
r = requests.get('http://www.baidu.com')
print(type(r.status_code),r.status_code)
print(type(r.headers),r.headers)
print(type(r.cookies),r.cookies)
print(type(r.url),r.url)
print(r.content)
print(r.text)

会话维持

假如我们第一个请求利用post()方法登录了网站,再想要用get()方法请求个人信息页面。实际上,这相当于打开了两个浏览器,是两个完全不相干的会话,所以是完全帮你获取个人信息的。这时我们就需要会话维持了。利用session我们可以轻易的做到这点而不用去进行繁琐的cookies操作。

import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456')
s.get('http://httpbin.org/cookies')

此时,进行的两个get请求是在同一个会话中进行的。

代理设置

如果我们需要设置代理,我们可以使用proxies参数。

import requests
proxies = {'http':'http://10.10.1.10:3128','https':'http://10.10.1.10:1080'}
requests.get('https://www.taobao.com',proxies=proxies)

超时设置

实际上,当我们直接写get请求时,如果服务器响应时间很久,此时对我们的爬虫影响很大,但它却永远也不会返回超时错误。
如果我们要求对服务器的响应时间进行一个限制,我们就需要用到一个参数timeout。

import requests
r = requests.get('https://www.baidu.com',timeout=1)

如果在1秒内程序没有相应,那么它会抛出一个异常。
实际上,请求分为两个阶段,连接和读取。上面设置的timeout是二者的时间总和,如果我们想要进行分别指定,可以采用以下方法

import requests
r = requests.get('https://www.baidu.com',timeout=(5,30))

如果想要永久等待,我们可以讲timeout设置为None,这也就和不加参数是一样的情况了。

身份验证

当我们遇到验证界面时,我们可以使用requests的验证功能。

import requests
r = requests.get('http://127.0.0.1:5000',auth=HTTPBasicAuth('linhong','1336659194'))

requests还提供了一个更简单的写法,可以直接传一个元组,它会默认使用HTTPBasicAuth这个类进行验证。

import requests
r = requests.get('http://127.0.0.1:5000',auth=('linhong','1336659194'))

re库与正则表达式

常用匹配规则

模式 描述
\w 匹配字母,数字及下划线
\W 匹配不是字母,数字及下划线的字符
\s 匹配任意空白字符(\t\n\r\f)
\S 匹配任意非空白字符
\d 匹配任意数字
\D 匹配任意非数字的字符
^ 匹配一行字符串的开头
$ 匹配一行字符串的结尾
. 匹配任意字符
[…] 用来匹配一组字符,如[abc]就是匹配a或b或c
[^…] 匹配不在[]中的字符,如[^abc]就是匹配非a,b,c的字符
* 匹配0个或多个表达式
+ 匹配1个或多个表达式
? 匹配0个或1个表达式
{n} 匹配n个前面的表达式
{n,m} 匹配n到m次前面的表达式

match()

import re
STR = 'su_shuo shi sha_bi'
result = re.match('su\w{4}',STR)
print(result)
print(result.group())
print(result.span())

运行结果如下:

<re.Match object; span=(0, 6), match='su_shu'>
su_shu
(0, 6)

可以看出,在match()方法中,第一个参数传入正则表达式,第二个参数传入要匹配的字符串。它会返回一个SRE_Match对象。该对象有两个方法,group()方法可以输出匹配到的内容,span()方法可以输出匹配的范围了。

多层匹配

import re
STR = 'su_shuo shi sha_bi'
result = re.match('su(\w{4})',STR)
print(result.group())
print(result.group(1))

我们可以在一个正则匹配式中用()包围其中一些语句从而形成多个分区,然后可以用group(1),group(2)……输出这些分区结果。

通用匹配

我们常用.*来匹配一切字符。需要注意的有以下两点。

在字符串中间我们尽量使用非贪婪匹配,也就是用.*?来代替.*,避免匹配缺失的情况。
如果匹配的结果在字符串结尾,.*?就有可能匹配不到任何内容了。

修饰符

.只是匹配除了换行符的其他所有字符,当遇到换行符的时候它就不会匹配了,有时候我们需要让它匹配所有字符。这个时候我们就需要用到换行符。

result = re.match('.*?',re.S)

此时.便可以匹配所有字符了。常用的修饰符还有re.I,它可以使匹配对大小写不敏感。

match()方法是从字符串开头开始匹配的,一旦开头不匹配,匹配就失败了。 所以我们一般使用search()方法进行匹配,search()方法的使用和match()类似,不再赘述。

findall()

前面所讲的match()还是search()都只能匹配正则表达式的第一个内容。如果我们想要获取匹配正则表达式的所有内容,我们就要借助findall()方法了。 它会将所有符合条件的字符串结果以一个数组的形式返回出来。

sub()

我们还可以用正则表达式来修改文本。这时我们就需要借助sub()方法了。

STR = 'ku_zhi_wen_ 666 kkkkk'
STR = re.sub('\d+','',content)

这里第一个参数传入需要匹配的正则表达式,第二个传入需要替换成的字符,第三个参数传入原字符。

compile()

compile()方法可以将正则表达式编译成正则表达式对象,在后面的过程可以直接引用。

pattern = re.compile('\d')
result = re.sub(pattern,'',html)

爬虫小练习(抓取猫眼电影排行)

这次的练习就不说出详细的过程了,直接上代码吧。

import json
import requests
from requests.exceptions import RequestException
import re
import time

# 通用抓取网页
def get_one_page(url):
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36'
        }
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        return None


def parse_one_page(html):
    pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a'
                         + '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
                         + '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
    items = re.findall(pattern, html)
    for item in items:
        yield {
            'index': item[0],
            'image': item[1],
            'title': item[2],
            'actor': item[3].strip()[3:],
            'time': item[4].strip()[5:],
            'score': item[5] + item[6]
        }


def write_to_file(content):
    with open('result.txt', 'a', encoding='utf-8') as f:
        f.write(json.dumps(content, ensure_ascii=False) + '\n')


def main(offset):
    url = 'http://maoyan.com/board/4?offset=' + str(offset)
    html = get_one_page(url)
    for item in parse_one_page(html):
        print(item)
        write_to_file(item)


if __name__ == '__main__':
    for i in range(10):
        main(offset=i * 10)
        time.sleep(1)

觉得主要写这个爬虫关键就是写好正则,正则写好了其他都不是问题。。。。