目录

第一个爬虫

目录
警告
本文最后更新于 2022-07-01,文中内容可能已过时。

摘要

在Python中,一个完整的爬虫(互联网蜘蛛)的实现方式多种多样,但主要过程还是两步:

伪装HTTP Request并获取相应的HTML文件(包括且不限于CSS、JS等内容); 解析HTML(XML或DOM Tree),获取需要的数据; ​ 在第一步中,常用的方法是使用urllib和urllib2(在Python3中这两个包已经合为一个包)来实现对网页资源的获取。当然,官方文档其实更推荐使用第三方库:requests。

  • urllib(2)模块是Python标准库中用于处理URL的组件合集;
  • requests是在urllib之上的HTTP客户端接口,某种意义上是一层高级的封装。

在第二步中,要解析扒下来的HTML文件(及其他),常用的是正则表达式(regex)和BeautifulSoup两种(lxml暂不做考虑,因为BS实际上可以用lxml来做解析引擎)。

  • 正则表达式(regex)的学习难度视情况而定,如果之前有其他语言的正则表达式基础,对于Python中的正则表达式也能很快上手。
  • BeautifulSoup上手更快,语言也更加偏自然化,但是有些编写不那么严谨的网页用BS可能很难解析出来,这时候就需要搭配正则表达式来做提取。

但这些方法某种意义上还是不那么方便,于是便有了Scrapy这种高级抽象的爬虫框架。(它不仅仅可以用来抓Web数据)

从学习难度和操作难度上,从urllib+regex、requests+BeautifulSoup到Scrapy,抽象程度依次加大,方便程度越来越好,但对底层的掌握能更好帮你理解一些实际操作时的Eoor和解析失败的原因。第一个爬虫,我们使用urllib+正则表达式的基础方法来实现。

首先我们先试着抓取百度首页的HTML内容

1
2
3
4
5
6
7
8
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import urllib.request
import urllib
url = 'http://www.baidu.com/'
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
print(content)

抓取网易云音乐歌单

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'
}
#nn163_cloud_url = 'http://music.163.com/playlist?id=2208261223'
nn163_cloud_url = 'https://music.163.com/playlist?id=889892039'

s = requests.session()
bs = BeautifulSoup(s.get(nn163_cloud_url, headers=headers).content, "lxml")
for i in bs.ul.children:
#    f = open("out.txt", "w")	#只写入一条数据。
    f = open('out.txt','a',encoding ='utf-8')
#    print (i.string)   #直接打印在屏幕上
    print (i.string, file = f)  #打印到文件

抓取豆瓣图书Top 250

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import requests
import mysql.connector
from idna import unicode
from bs4 import BeautifulSoup


__author__ = 'Carlos Leo'

id = 0

# 获取网页返回信息
def get_response(page):
    resp = requests.get('https://book.douban.com/top250', params={'start': str(page * 10)})
    if resp.status_code == 200:
        return resp.text
    else:
        raise RecursionError('fail to request to target.')


# 使用BeautifulSoup解析
def parse_html(html):
    soup = BeautifulSoup(html, 'lxml')
    tables = soup.find('div', id='wrapper').find_all('table')
    for table in tables:
        img = table.find('img')['src']
        name = table.select('.pl2')[0].a['title']
        string = unicode(table.find('p').string)
        lst = string.split(' / ')
        author = lst[0].strip()
        publisher = lst[-3].strip()
        date = lst[-2].strip()
        price = lst[-1].strip()
        credit = unicode(table.select('.rating_nums')[0].string)
        try:
            desc = unicode(table.select('.inq')[0].string)
        except IndexError:
            desc = '无'
        global id
        id += 1
        yield {
            'id': id,
            'img': img,
            'name': name,
            'author': author,
            'publisher': publisher,
            'date': date,
            'price': price,
            'credit': float(credit),
            'desc': desc
        }


# 写入文件
# def write_to_file():
#     with open('books.txt', 'w') as f:
#         for i in range(10):
#             for book in parse_html(get_response(i)):
#                 json.dump(book, f, ensure_ascii=False)
#                 f.write('\n')
#                 print(book, 'was saved into book.txt')


conn = mysql.connector.connect(host='192.168.1.71', user='root', password='root', database='message')
cursor = conn.cursor()
#创建表
cursor.execute('create table book (id int(11) primary key,img varchar(100),name varchar(30),author varchar(30),publisher varchar(30),date varchar(20),price varchar(15),credit float,description varchar(30))')
# 存入数据库
def save():
    for i in range(10):

        for book in parse_html(get_response(i)):
            save_to_db(book['id'], book['img'], book['name'], book['author'], book['publisher'], book['date'],
                       book['price'], book['credit'], book['desc'])
            print('save book' + str(book) + 'to db')


# 存入一本书到数据库

def save_to_db(*args):
    conn = mysql.connector.connect(host='192.168.1.71',user='root', password='root', database='message')
    cursor = conn.cursor()
    cursor.execute('insert into book(id, img, name, author, publisher, date, price, credit, description) '
                   'values(%s, %s, %s, %s, %s, %s, %s, %s, %s)', args)
    conn.commit()
    cursor.close()
    conn.close()
if __name__ == '__main__':
    save()