Python玩转爬虫(1)

Posted by JD on May 17, 2019

Request

Request是一个优雅而简单的Python的HTTP库。我们可以使用它来爬取大部分网站的数据。

先导入Requests模块

import requests

获取网页,以百度(https://www.baidu.com/)为例

url = 'https://www.baidu.com/'
#r = requests.request('GET', url)
r = requests.get(url)

一些常用的信息

网页链接、cookies、编码、响应头、是否重定向、响应状态码

r.url
r.cookies
r.encoding
r.headers
r.is_redirect
r.status_code

Requests附带了一个内置的状态码查询对象,具体可以看这个链接

requests.codes['ok'] == 200    # True
requests.codes['requested_range']    # 416

制定属于自己的请求头,可以打开网站,查看Network,点击一个页面文件

找到Request Headers

简单地传递一个dictheaders参数就可以

headers = {
    'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36'
                   ' (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'),
    'Host': 'www.baidu.com',
    'Cache-Control': 'max-age=0',
    'Accept-Language': 'zh-CN,zh;q=0.9'
}
r = requests.get(url, headers=headers)

Requests还可以发送更加复杂的POST请求

payload = {'key1': 'value1', 'key2': 'value2'}

r = requests.post("http://httpbin.org/post", data=payload)
print(r.text)
{
  ...
  "form": {
    "key2": "value2",
    "key1": "value1"
  },
  ...
}

网站有账号密码也没问题,可以在GET之前,先POST加入登录信息,使用session,Requests会自动保持cookies,就可以尽情爬取该网站。

这边就以登录马蜂窝为例,我们要POST登录信息,这些信息在Network里面寻找。

可是在里面没有找到需要传的哪些登录信息。这时,我们可以先用个错误的登录用户名和密码来登录一次,为什么不用正确的用户名和密码,由于正确登录会跳转页面,这样就看不到究竟传了哪些信息。

我们发现需要传passportpassword,现在可以开始我们的代码

import requests

url = "https://passport.mafengwo.cn/login/"

data = {
    'passport': 'username',
    'password': 'password',
    'code': ''
}

headers = {
    "Referer": "https://passport.mafengwo.cn/",
    'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36'
                   ' (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36')
}

s = requests.session()
s.post(url, data=data, headers=headers)

route_url = "http://www.mafengwo.cn/plan/route.php"
r = s.get(route_url, headers=headers)

r.url    # http://www.mafengwo.cn/plan/route.php

如果直接GET这个网址的话,是会返回登录页面

route_url = "http://www.mafengwo.cn/plan/route.php"
r = requests.get(route_url, headers=headers)
r.url    # https://passport.mafengwo.cn?return_url=http%3A%2F%2Fwww.mafengwo.cn%2Fplan%2Froute.php

每个网站的登录信息并不都一样,但是总能找到所需传的参数。

Requests还有许多别的用法,详情可见官方文档

BeautifulSoup

BeautifulSoup4是一个可以从HTML或XML文件中提取数据的Python库,具有良好的解析功能。目前我使用的BeautifulSoup4的版本是4.7.1

bs4除了支持Python标准库中的HTML解析器,还支持一些第三方的解析器,比如lxml。下表列出了主要的解析器,以及它们的优缺点。

下边解析百度新闻首页。

首先,爬取网页源代码

import requests

baidu_url = "http://news.baidu.com/"
r = requests.get(baidu_url)
html = r.text

爬取到的html是个字符串,可以通过bs4,能够得到一个BeautifulSoup的对象,并能按照标准的缩进格式的结构输出。

from bs4 import BeautifulSoup

html_bs4 = BeautifulSoup(html, 'lxml')
print(html_bs4.prettify())

接着,我们就需要在html_bs4中定位我们所需要数据的位置。

  1. 标签来定位一些简单的数据,这种需要注意,只匹配第一个标签

     title = html_bs4.title
     print(title)    # '<title>百度新闻——海量中文资讯平台</title>'
    
  2. CSS定位数据,可以查找到大部分数据

     title = html_bs4.select("title")    # 根据标签
     print(title)    # [<title>百度新闻——海量中文资讯平台</title>]
    
     search_btn = html_bs4.select("#search-btn")    # 根据id
     print(search_btn)    # [<a href="javascript:void(0);" id="search-btn">搜索</a>]
    
     submit_btn = html_bs4.select(".submit-btn")    # 根据class属性
     print(submit_btn)    # [<button class="submit-btn" type="button">搜索</button>]
        
     search_btn = html_bs4.select("a[id='search-btn']")    # CSS属性
     print(search_btn)    # [<a href="javascript:void(0);" id="search-btn">搜索</a>]
        
     img = html_bs4.select("li span[class='img-container'] img")
     print(img)     # [<img src="//gss0.bdstatic.com/5foIcy0a2gI2n2jgoY3K/static/fisp_static/common/img/sidebar/1014720a_d31158d.png"/>]
    
  3. 正则表达式可以定位到任意数据

     import re
        
     title = re.search(r'<title\S*title\>', html).group()
     print(title)    # <title>百度新闻——海量中文资讯平台</title>
    

还有find_allfind等经常使用的方法。

详情可看官方文档