0%

爬虫初体验-网站文章

日期:2019-05-09
天气:没出门我也不知道……
啊啊啊啊啊(请自行带入Do、Re、Mi)~今天是有点艹dan又有点满足的一天。艹dan是因为,就因为同学让我帮忙就捣鼓了一天 python 爬虫,茶不思饭不想;满足就是一天过去了还是有很多收获,也掌握了一些 python 爬虫的基本技能。

目标任务

需求是爬取康安途网站医药新闻板块的所有文章,希望得到的包括每一篇文章的标题及其内容(纯文本)。
大概浏览了一下页面的内容,新闻版块一共有 2317 页,每一页包含 20 篇文章,也就是实说最后会有 40k+ 条信息,我的小本本还是有点承受不住的……
本来我都准被写到一个个文件里了,后来嘞,需求改了,变成把 [标题,日期,链接] 存到一个 excel 表格里,大概就酱紫。
最后我还是手欠把内容给加上了。

工具安装

anaconda 安装

1
2
$ conda install requests
$ conda install beautifulsoup4

pip 安装
1
2
$ pip install requests
$ pip install beautifulsoup4

基本思路

  • 使用 requests + BeautifulSoup 获取网页的源代码并对其解析
  • 使用 BeautifulSoup 中的 find 函数找到 文章名称、链接网址、发表时间 所在的 tag
  • 使用 BeautifulSoup 中的 string/属性 从我们找到的 tag 提取需要的信息
  • 通过之前提取出的网址,抓取该页面中的文章内容,大致步骤同上
  • 使用 pandas 生成 excel 文件,我是感觉这个比较简便快捷
  • 因为信息数量太大了,所以使用多个文件来保存

遇到的问题

一开始由于完全没经验,直接就去网上开始搜 “python爬取网站所有文章”,还是找到了两片比较有用的,虽然说由于每个网站的结构相差比较多,不一样的地方还是多,不过因为这两篇文章还是知道了常用的库以及基本用法。

requests - BeautifulSoup 乱码问题

! 叮!这里的代码是错误不完全示范!
使用 requests - BeautifulSoup 解析网页源代码,最开始两篇文章中是这样的:

1
2
3
4
url = "https://www.kangantu.com/news"
req = requests.get(url)
bs = BeautifulSoup(req.text)
bf = bs.find_all("a", class_="tiltle")

然后就发现什么也找不到,相当于一部分内容直接丢失了……然后看了看 BeautifulSoup 的文档,借鉴了一下别人的代码。如下修改:
1
2
3
4
5
6
7
url = "https://www.kangantu.com/news"
req = requests.get(url)
#新增:
req.encoding = 'utf-8'
bs = BeautifulSoup(req.text, "html.parser")

bf = bs.find_all("a", class_="tiltle")

倒腾来倒腾去,还是不对,虽然没有内容丢失,但中文部分还是会乱码。大半天被这问题困扰,终于我灵机一动,搜索 “BeautifulSoup 乱码” ,成功找到这篇文章,解决了问题,不过没有完全按照这个修改哈。
总结以下嘞,就是在使用 requests + BeautifulSoup 获取源代码的时候,最好能够声明网页的编码格式,编码格式源代码里可以看到,最终如下:

如何获得网站编码格式:
使用 Chrome 浏览器,进入需要爬取的网页,鼠标右键进入源代码界面;
Ctrl + f 搜索 “charset” 即可

1
2
3
4
5
6
7
url = "https://www.kangantu.com/news"
req = requests.get(url)
#修改:
req.encoding = 'gb2312'

bs = BeautifulSoup(req.text, "html.parser")
bf = bs.find_all("a", class_="tiltle")
如何获得需要的部分

一开始因为信息丢失和乱码问题,止步不前,一发同学用 python-2.7 + urllib2 + re 解决了文章标题和链接地址的问题,但是我真的非常不喜欢用 re ,看到就晕那种,磨啊磨一直到解决了乱码问题,后面的也就迎刃而解了,如下:

1
2
3
4
5
6
7
8
htmlr = requests.get(url)
htmlr.encoding = 'gb2312'
bs = BeautifulSoup(htmlr.text, "html.parser")
title_link = bs.find("div", class_="listbox").find_all("a", class_="title")
date = bs.find_all("span", class_="article-date")
title_list = list(item.string for item in title_link) #得到包含标题的列表
link_list = list(item['href'] for item in title_link) #得到包含网址的列表
date_list = list(item.string for item in date) #得到包含日期的列表

窝嘞代码

最后,贴一下所有的代码~

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# -*- coding: UTF-8 -*-
"""
date: 2019-5-9
fucntion: get all the article of a network station
author: Li yinian
version: v-1.1
python-3.7
新增:对不完整网址的补全
新增:抓取文章的内容
"""

#引入模块
import re
import requests
from bs4 import BeautifulSoup
import pandas as pd

#生成包含所有网址的列表
def generate_url_list(page_list):
"""
输入:页码范围,要求格式为 list
输出:包含要抓取信息的所页面网址的列表
"""
basic_url = "https://www.kangantu.com/news/list_"
url_list = []

for i in page_list:
url = basic_url+str(i)+".html"
url_list.append(url)

return url_list


#新增函数,用于转换不完整网址
def url_trans(url):
if url[:5] != 'https':
link = "https://www.kangantu.com" + url
else:
link = url
return link


#获取页面的文章题目,时间,以及文章链接
def get_title_link_date(url):
"""
输入:网址链接(str)
输出:DataFrame, columns=["title", "data", "link"]
"""
htmlr = requests.get(url)
htmlr.encoding = 'gb2312'
bs = BeautifulSoup(htmlr.text, "html.parser")
title_link = bs.find("div", class_="listbox").find_all("a", class_="title")

date = bs.find_all("span", class_="article-date")
title_list = list(item.string for item in title_link) #得到包含标题的列表

#修改:url_trans()函数补全网址
#link_list = list(item['href'] if for item in title_link)
link_list_0 = list(item['href'] for item in title_link)
link_list = list(map(url_trans, link_list_0)) #得到包含网址的列表

date_list = list(item.string for item in date) #得到包含日期的列表

title_date_link_df = pd.DataFrame({'title': title_list, 'date': date_list, 'link': link_list}) #

return title_date_link_df


#新增:通过已获得的文章地址抓取文章的内容,得到包含日期的列表
def get_content(link_list):
"""
输入:列表-内容为已获取的文章网址
输出:对应文章内容的列表
"""
content_list = []

for url in link_list:
htmlr = requests.get(url)
htmlr.encoding = 'gb2312'
bs = BeautifulSoup(htmlr.text, "html.parser")
content = bs.find("div", class_="content")
content_list.append(content.get_text())

return content_list



#生成excel文件
def to_excel_file(file_df, file_path):
"""
输入:DataFrame格式的文件,文件路径-包括名称,sheet编号
"""
#writer = pd.ExcelWriter(file_path)
file_df.to_excel(file_path, index=False, encoding='utf-8', sheet_name=str(file_index))


def last_func(page_list, file_index):
urls = generate_url_list(page_list)
df = pd.DataFrame()
for url in urls:
title_date_link_df = get_title_link_date(url)

#新增:加入文章内容
link_list = title_date_link_df['link']
title_date_link_df['content'] = get_content(link_list)

df = pd.concat([df, title_date_link_df], axis=0, ignore_index=True)
#修改:修改文件夹名称
to_excel_file(df, "/home/may/daydayup/kangantu-more/kangantu-news-"+str(file_index)+".xls")


#正式的代码部分,网站需要爬取的共 2317 页-rang(1,2318)
list_n = list(range(1, 2318, 50))
list_n.append(2318)
page_hole_list = [list(range(list_n[i-1], list_n[i])) for i in range(1, len(list_n))]

for i in range(len(page_hole_list)):
file_index = i
page_list = page_hole_list[i]
last_func(page_list, file_index+1)