赞
踩
以下内容根据个人学习总结
对于一些静态页面而言,爬取相关数据比较简单,主要思路是首先获取网页链接,然后定位数据源码,最后获取其内容
以下任务目标为爬取盗墓笔记第一部全文,网页地址为盗墓笔记1:七星鲁王宫
后续代码均在 Windows + python 3.7.2 实现,调试用的是 Pycharm Community ,实际上 Visual Studio Code 更加轻量,但是IDE比较适合刚入门的。
使用到的库包括 requests
和 bs4
,如果没有安装这两个库,可以直接在cmd中使用下面的命令进行安装
pip install requests
pip install bs4
talk is cheap, show you the code
''' 该函数将获取目录页所有章节名及其对应链接 ''' def get_catalog(url): # url = 'http://www.daomubiji.com/dao-mu-bi-ji-1' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36' } html = requests.get(url, headers=headers) soup = BeautifulSoup(html.content, 'lxml') soup_catalog = soup.find_all('article', class_='excerpt excerpt-c3') catalogs = BeautifulSoup(str(soup_catalog)).find_all('a') names = [] hrefs = [] for c in catalogs: names.append(c.text) hrefs.append(c.attrs['href']) return names, hrefs
'''
该函数将获取章节页主体文本
'''
def get_one_chapter(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36'
}
html = requests.get(url, headers=headers)
soup = BeautifulSoup(html.content, 'lxml')
soup_text = soup.find('article')
return soup_text.text
有了上面2个函数,我们就可以组合起来获得整本书的内容,以下为最终实现代码
#!usr/bin/env python # -*- encoding:utf-8 -*- __author__ = 'xx' __date__ = '2019-07-29' import requests from bs4 import BeautifulSoup def get_catalog(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36' } html = requests.get(url, headers=headers) soup = BeautifulSoup(html.content, 'lxml') soup_catalog = soup.find_all('article', class_='excerpt excerpt-c3') catalog = BeautifulSoup(str(soup_catalog), 'lxml').find_all('a') names = [] hrefs = [] for c in catalog: names.append(c.text) hrefs.append(c.attrs['href']) return names, hrefs def get_one_chapter(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36' } html = requests.get(url, headers=headers) soup = BeautifulSoup(html.content, 'lxml') soup_text = soup.find('article') return soup_text.text def get_textbook(url): text = '' names, hrefs = get_catalog(url) index = 1 for name, href in zip(names, hrefs): content = get_one_chapter(href) text += '第{0}章 {1}\n'.format(index, name) + content + '\n\n' return text def write_to_file(filepath, text): with open(filepath, 'a+') as f: f.write(text) def main(): filepath = './Files/dmbj1.txt' root_url = 'http://www.daomubiji.com/dao-mu-bi-ji-1' write_to_file(filepath, get_textbook(root_url)) if __name__ == '__main__': main()
对于一些网页来说,其数据并不是在页面本身,而是当页面打开后页面调用js脚本与服务器进行交互,从而改变网页数据,也就是 ajax
,因此仅对目标页面发起普通的 get
请求是无法获得需要的数据的,这时候应该从网页加载找真正请求的目标
以下代码任务为抓取中国数据网的年度人口基本情况中的表格数据
对于想要查找网页的网络活动,常用的是使用抓包工具(比如:Flidder)进行抓包,这里简单的使用 Chrome
浏览器的审查元素中的 Network
活动从而找到请求目标
从该图中可以看出,当点击 人口基本情况 时,有两条XHR数据出现在 Network 中,通过对比可以发现,我们所需要的数据恰巧包含在 tablequery.htm?m=QueryData&code=AD03&wds=%5B%7B%22wdcode%22%3A%22reg%22%2C%22valuecode%22%3A%22000000%22%7D%5D
该条数据的 htmltable
中(通过查看Preview可以预览响应转化后的内容,通过查看Response可以查看响应的内容,是一个json数据格式。
故此,我们获得了数据真正的请求源为: http://data.stats.gov.cn/tablequery.htm?m=QueryData&code=AD03&wds=%5B%7B%22wdcode%22%3A%22reg%22%2C%22valuecode%22%3A%22000000%22%7D%5D
动态网页数据一般都是 json
格式的字符串,因此还需要导入 json
库将 json
格式的字符串转化为 python
中的 dict
使用
有了前面的铺垫,这里直接上最终实现代码
#!usr/bin/env python # -*- encoding:utf-8 -*- __author__ = 'xx' __date__ = '2019-07-29' import requests from bs4 import BeautifulSoup import json import pandas as pd def main(): url = 'http://data.stats.gov.cn/tablequery.htm?m=QueryData&code=AD03&wds=%5B%7B%22wdcode%22%3A%22reg%22%2C%22valuecode%22%3A%22000000%22%7D%5D' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36' } response = requests.get(url, headers=headers) data = json.loads(response.text)['htmltable'] soup = BeautifulSoup(data, 'lxml') trs = soup.find_all('tr') table = [] index = 1 for tr in trs: row = [] if index == 1: ts = tr.find_all('th') else: ts = tr.find_all('td') for th in ts: row.append(th.text) table.append(row) index += 1 df = pd.DataFrame(table) df.to_excel('./Files/table.xlsx', index=False) if __name__ == '__main__': main()
刚刚翻阅了一篇博客:Python requests模块params与data的区别,发现可以采用另一种方式获取 json
数据
参照上图,调到 Headers
部分,往下找到 Request Headers
,将这些作为 get
请求中的 headers
部分,然后翻到最下面有一个 Query String Parameters
这个就是数据源接口中传入的参数,如果使用过第三方api肯定很熟悉这个 url
的格式,就相当于是在调用 http://data.stats.gov.cn/tablequery.htm
接口,然后参数为 m=QueryData
code=AD03
wds=[{'wdcode':'reg','valuecode':'000000'}]
这三个,组合成的 url
然后使用 get
方法获得数据
所以我们可以直接使用调用接口的方式去获得数据,该段代码如下
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Host': 'data.stats.gov.cn', 'X-Requested-With': 'XMLHttpRequest' } api_url = 'http://data.stats.gov.cn/tablequery.htm' params = { 'm': 'QueryData', 'code': 'AD03', 'wds': '[{"wdcode":"reg","valuecode":"000000"}]' } # 注意,wds这个键对应的值并不是一个字典或者列表,网页接口传的参数始终都是会组成字符串格式 html = requests.get(url, headers=headers, params=params) data = json.loads(html.text)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。