Python网络数据采集3-数据存到CSV以及MySql
先热热身,下载某个页面的所有图片。
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/52.0.2743.116 Safari/537.36 Edge/15.16193'}
start_url = 'https://www.pythonscraping.com'
r = requests.get(start_url, headers=headers)
soup = BeautifulSoup(r.text, 'lxml')
# 获取所有img标签
img_tags = soup.find_all('img')
for tag in img_tags:
print(tag['src'])
https://www.pythonscraping.com/sites/default/files/lrg_0.jpg
http://pythonscraping.com/img/lrg%20(1).jpg
将网页表格存储到CSV文件中
以这个网址为例,有好几个表格,我们对第一个表格进行爬取。Wiki-各种编辑器的比较
import csv
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/52.0.2743.116 Safari/537.36 Edge/15.16193'}
url = 'https://en.wikipedia.org/wiki/Comparison_of_text_editors'
r = requests.get(url, headers=headers)
soup = BeautifulSoup(r.text, 'lxml')
# 只要第一个表格
rows = soup.find('table', class_='wikitable').find_all('tr')
# csv写入时候每写一行会有一空行被写入,所以设置newline为空
with open('editors.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
for row in rows:
csv_row = []
for cell in row.find_all(['th', 'td']):
csv_row.append(cell.text)
writer.writerow(csv_row)
需要注意的有一点,打开文件的时候需要指定newline=''
,因为写入csv文件时,每写入一行就会有一空行被写入。
从网络读取CSV文件
上面介绍了将网页内容存到CSV文件中。如果是从网上获取到了CSV文件呢?我们不希望下载后再从本地读取。但是网络请求的话,返回的是字符串而非文件对象。csv.reader()
需要传入一个文件对象。故需要将获取到的字符串转换成文件对象。Python的内置库,StringIO和BytesIO可以将字符串/字节当作文件一样来处理。对于csv模块,要求reader迭代器返回字符串类型,所以使用StringIO,如果处理二进制数据,则用BytesIO。转换为文件对象,就能用CSV模块处理了。
下面的代码最为关键的就是data_file = StringIO(csv_data.text)
将字符串转换为类似文件的对象。
from io import StringIO
import csv
import requests
csv_data = requests.get('http://pythonscraping.com/files/MontyPythonAlbums.csv')
data_file = StringIO(csv_data.text)
reader = csv.reader(data_file)
for row in reader:
print(row)
['Name', 'Year']
["Monty Python's Flying Circus", '1970']
['Another Monty Python Record', '1971']
["Monty Python's Previous Record", '1972']
['The Monty Python Matching Tie and Handkerchief', '1973']
['Monty Python Live at Drury Lane', '1974']
['An Album of the Soundtrack of the Trailer of the Film of Monty Python and the Holy Grail', '1975']
['Monty Python Live at City Center', '1977']
['The Monty Python Instant Record Collection', '1977']
["Monty Python's Life of Brian", '1979']
["Monty Python's Cotractual Obligation Album", '1980']
["Monty Python's The Meaning of Life", '1983']
['The Final Rip Off', '1987']
['Monty Python Sings', '1989']
['The Ultimate Monty Python Rip Off', '1994']
['Monty Python Sings Again', '2014']
DictReader可以像操作字典那样获取数据,把表的第一行(一般是标头)作为key。可访问每一行中那个某个key对应的数据。
每一行数据都是OrderDict
,使用Key可访问。看上面打印信息的第一行,说明由Name
和Year
两个Key。也可以使用reader.fieldnames
查看。
from io import StringIO
import csv
import requests
csv_data = requests.get('http://pythonscraping.com/files/MontyPythonAlbums.csv')
data_file = StringIO(csv_data.text)
reader = csv.DictReader(data_file)
# 查看Key
print(reader.fieldnames)
for row in reader:
print(row['Year'], row['Name'], sep=': ')
['Name', 'Year']
1970: Monty Python's Flying Circus
1971: Another Monty Python Record
1972: Monty Python's Previous Record
1973: The Monty Python Matching Tie and Handkerchief
1974: Monty Python Live at Drury Lane
1975: An Album of the Soundtrack of the Trailer of the Film of Monty Python and the Holy Grail
1977: Monty Python Live at City Center
1977: The Monty Python Instant Record Collection
1979: Monty Python's Life of Brian
1980: Monty Python's Cotractual Obligation Album
1983: Monty Python's The Meaning of Life
1987: The Final Rip Off
1989: Monty Python Sings
1994: The Ultimate Monty Python Rip Off
2014: Monty Python Sings Again
写入数据库中
数据库使用MySql
如果服务没有后启动,首先启动服务。net start mysql57
这里57是版本号,根据自己的版本填写。
然后mysql -u root -p
输入密码后就可以使用了。
先来简单复习下SQL语法。
SQL基本语法
下面是关于数据库的操作
-
create database example;
这样创建一个叫做example的数据库。 -
drop database example;
则是删除这个数据库。 -
show databases;
可以查看所有数据库。 -
use example;
使用这个数据库。select database();
显示当前正在使用的数据库。
下面是关于表的操作
-
show tables;
查看当前数据库下的所有表。 -
desc some_table;
查看某个表的具体结构。 -
drop table some_table;
删除某个表。 -
alter table some_table add age int;
加一列 -
alter table some_table drop age;
删除一列
下面是表的CURD
-
insert into t_user(name, email) values('tom','tom@163.com');
添加一行数据,可以指定任意列的内容,剩下的要么自己生成(如id一般自增),要么就是默认值。 -
UPDATE t_user SET NAME='rose' WHERE id=7;
更新数据,表示将id为7的数据name改为rose。 -
DELETE FROM t_user WHERE NAME='God';
把name是God的记录删除。DELETE FROM t_user;
删除整张表中所有记录. -
select * from stu;
查询stu表里所有数据,*
是通配符匹配所有。 -
select sname from stu;
查询stu的sname那列。 -
select * from stu where gender='female' and age<50;
条件查询。
使用pymysql连接到MySql
Python连接MySql,这里使用pymysql
import pymysql
conn = pymysql.connect(host='localhost', user='root', password='admin', db='example',charset='utf8')
cur = conn.cursor()
try:
# 上面填了参数这句就不是必须的
# cur.execute('USE example')
cur.execute('SELECT * FROM pages')
print(cur.fetchone())
finally:
cur.close()
conn.close()
(1, 'Test Title', '方法', datetime.datetime(2017, 7, 15, 15, 45, 46))
db
参数表示选择的数据库名称。连接数据库时候,加上charset=utf8
可以处理中文字符。注意不要写成utf-8
。然后就是连接和光标都要记得close。
接下来从某个wiki页面开始,随机获取一个词条访问其页面,并储存词条的标题(title)和正文第一段(content)到MySql。
建表。
create TABLE pages(id int primary key auto_increment,title varchar(200),content varchar(10000),created timestamp default current_timestamp);
上代码
import re
import random
import pymysql
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/52.0.2743.116 Safari/537.36 Edge/15.16193'}
conn = pymysql.connect(host='localhost', user='root', password='admin', db='example', charset='utf8')
cur = conn.cursor()
# 存到数据库
def store(title, content):
try:
cur.execute(f"INSERT INTO pages(title, content) VALUES('{title}', '{content}');")
except Exception as e:
print(e)
else:
conn.commit()
# 获得页面内所有词条的链接
def get_links(article_url):
r = requests.get('https://en.wikipedia.org' + article_url, headers=headers)
soup = BeautifulSoup(r.text, 'lxml')
title = soup.h1.string
content = soup.find('div', id='mw-content-text').find('p').text
store(title, content)
links = soup.find('div', id='bodyContent').find_all('a', href=re.compile('^/wiki/[^:/]*$'))
return links
link_list = get_links('/wiki/Kevin_Bacon')
try:
while len(link_list) > 0:
new_article = random.choice(link_list).get('href')
print(new_article)
link_list = get_links(new_article)
finally:
cur.close()
conn.close()
conn.commit()
注意这句,由于连接不是自动提交的,需要我们手动提交,确保数据确实改变。有些词条的可能会导致在执行查询语句的时候发生异常,处理一下,不让其终止爬取。看下结果。
保存链接之间的联系
比如链接A,能够在这个页面里找到链接B。则可以表示为A -> B
。我们就是要保存这种联系到数据库。先建表:
pages表只保存链接url。
CREATE TABLE `pages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) DEFAULT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
links表保存链接的fromId和toId,这两个id和pages里面的id是一致的。如1 -> 2
就是pages里id为1的url页面里可以访问到id为2的url的意思。
CREATE TABLE `links` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fromId` int(11) DEFAULT NULL,
`toId` int(11) DEFAULT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`);
上面的建表语句看起来有点臃肿,我是先用可视化工具建表后,再用show create table pages
这样的语句查看的。
import re
import pymysql
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/52.0.2743.116 Safari/537.36 Edge/15.16193'}
conn = pymysql.connect(host='localhost', user='root', password='admin', db='wiki', charset='utf8')
cur = conn.cursor()
def insert_page_if_not_exists(url):
cur.execute(f"SELECT * FROM pages WHERE url='{url}';")
# 这条url没有插入的话
if cur.rowcount == 0:
# 那就插入
cur.execute(f"INSERT INTO pages(url) VALUES('{url}');")
conn.commit()
# 刚插入数据的id
return cur.lastrowid
# 否则已经存在这条数据,因为url一般是唯一的,所以获取一个就行,取脚标0是获得id
else:
return cur.fetchone()[0]
def insert_link(from_page, to_page):
print(from_page, ' -> ', to_page)
cur.execute(f"SELECT * FROM links WHERE fromId={from_page} AND toId={to_page};")
# 如果查询不到数据,则插入,插入需要两个pages的id,即两个url
if cur.rowcount == 0:
cur.execute(f"INSERT INTO links(fromId, toId) VALUES({from_page}, {to_page});")
conn.commit()
# 链接去重
pages = set()
# 得到所有链接
def get_links(page_url, recursion_level):
global pages
if recursion_level == 0:
return
# 这是刚插入的链接
page_id = insert_page_if_not_exists(page_url)
r = requests.get('https://en.wikipedia.org' + page_url, headers=headers)
soup = BeautifulSoup(r.text, 'lxml')
link_tags = soup.find_all('a', href=re.compile('^/wiki/[^:/]*$'))
for link_tag in link_tags:
# page_id是刚插入的url,参数里再次调用了insert_page...方法,获得了刚插入的url里能去往的url列表
# 由此形成联系,比如刚插入的id为1,id为1的url里能去往的id有2、3、4...,则形成1 -> 2, 1 -> 3这样的联系
insert_link(page_id, insert_page_if_not_exists(link_tag['href']))
if link_tag['href'] not in pages:
new_page = link_tag['href']
pages.add(new_page)
# 递归查找, 只能递归recursion_level次
get_links(new_page, recursion_level - 1)
if __name__ == '__main__':
try:
get_links('/wiki/Kevin_Bacon', 5)
except Exception as e:
print(e)
finally:
cur.close()
conn.close()
1 -> 2
2 -> 1
1 -> 2
1 -> 3
3 -> 4
4 -> 5
4 -> 6
4 -> 7
4 -> 8
4 -> 4
4 -> 4
4 -> 9
4 -> 9
3 -> 10
10 -> 11
10 -> 12
10 -> 13
10 -> 14
10 -> 15
10 -> 16
10 -> 17
10 -> 18
10 -> 19
10 -> 20
10 -> 21
...
看打印的信息,一目了然。看前两行打印,pages
表里id为1的url可以访问id为2的url,同时pages
表里id为2的url可以访问id为1的url...依次类推。
首先需要使用insert_page_if_not_exists(page_url)
获得链接的id,然后使用insert_link(fromId, toId)
形成联系。fromId
是当前页面的url,toId则是从当前页面能够去往的url的id,这些能去往的url用bs4找到以列表形式返回。当前所处的url即page_id,所以需要在insert_link
的第二个参数中,再次调用insert_page_if_not_exists(link)
以获得列表中每个url的id。由此形成了联系。比如刚插入的id为1,id为1的url里能去往的id有2、3、4...,则形成1 -> 2, 1 -> 3这样的联系。
看下数据库。下面是pages
表,每一个id都对应一个url。
然后下面是links
表,fromId
和toId
就是pages
中的id
。当然和打印的数据是一样的咯,不过打印了看看就过去了,存下来的话哪天需要分析这些数据就大有用处了。
by @sunhaiyu
2017.7.15
Python网络数据采集3-数据存到CSV以及MySql的更多相关文章
-
[python] 网络数据采集 操作清单 BeautifulSoup、Selenium、Tesseract、CSV等
Python网络数据采集操作清单 BeautifulSoup.Selenium.Tesseract.CSV等 Python网络数据采集操作清单 BeautifulSoup.Selenium.Tesse ...
-
笔记之Python网络数据采集
笔记之Python网络数据采集 非原创即采集 一念清净, 烈焰成池, 一念觉醒, 方登彼岸 网络数据采集, 无非就是写一个自动化程序向网络服务器请求数据, 再对数据进行解析, 提取需要的信息 通常, ...
-
Python网络数据采集PDF高清完整版免费下载|百度云盘
百度云盘:Python网络数据采集PDF高清完整版免费下载 提取码:1vc5 内容简介 本书采用简洁强大的Python语言,介绍了网络数据采集,并为采集新式网络中的各种数据类型提供了全面的指导.第 ...
-
Python网络数据采集4-POST提交与Cookie的处理
Python网络数据采集4-POST提交与Cookie的处理 POST提交 之前访问页面都是用的get提交方式,有些网页需要登录才能访问,此时需要提交参数.虽然在一些网页,get方式也能提交参.比如h ...
-
Python网络数据采集1-Beautifulsoup的使用
Python网络数据采集1-Beautifulsoup的使用 来自此书: [美]Ryan Mitchell <Python网络数据采集>,例子是照搬的,觉得跟着敲一遍还是有作用的,所以记录 ...
-
Python网络数据采集PDF
Python网络数据采集(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/16c4GjoAL_uKzdGPjG47S4Q 提取码:febb 复制这段内容后打开百度网盘手 ...
-
Python网络数据采集7-单元测试与Selenium自动化测试
Python网络数据采集7-单元测试与Selenium自动化测试 单元测试 Python中使用内置库unittest可完成单元测试.只要继承unittest.TestCase类,就可以实现下面的功能. ...
-
Python网络数据采集6-隐含输入字段
Python网络数据采集6-隐含输入字段 selenium的get_cookies可以轻松获取所有cookie. from pprint import pprint from selenium imp ...
-
Python网络数据采集2-wikipedia
Python网络数据采集2-wikipedia 随机链接跳转 获取*的词条超链接,并随机跳转.可能侧边栏和低栏会有其他链接.这不是我们想要的,所以定位到正文.正文在id为bodyContent的 ...
随机推荐
-
CH Round #72 奇数码问题[逆序对 观察]
描述 你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中. 例如:5 2 81 3 _4 6 7 在游戏过程中,可以把空格与其上 ...
-
AP创建会计科目
一. 创建会计科目的途径 1. 在发票工作台对单张发票进行创建科目: 2. 提交“创建会计科目”并发请求,对所有已经验证但尚未创建会计科目的发票进行创建会计科目. 二. 对单张发票创建会计科目 发票在 ...
-
POJ 3009
http://poj.org/problem?id=3009 一个搜索的题目: 大意就是一个冰球,在冰面上滑动,你打击一次,就沿一个反向滑动,知道碰到墙就会停下,而墙则会破碎. 求从起点到终点的最短的 ...
-
【Ext.Net学习笔记】05:Ext.Net GridPanel的用法(包含Filter、Sorter、Grouping、汇总(Summary)的用法)
GridPanel是用来显示数据的表格,与ASP.NET中的GridView类似. GridPanel用法 直接看代码: <ext:GridPanel runat="server&qu ...
-
对 cloudwu 简单的 cstring 进行简单解析
题外话 以前也用C写过字符串,主要应用的领域是,大字符串,文件读取方面.写的很粗暴,用的凑合着.那时候看见云风前辈的一个开源的 cstring 串. 当时简单观摩了一下,觉得挺好的.也没细看.过了较长 ...
-
KNN及其改进算法的python实现
一. 马氏距离 我们熟悉的欧氏距离虽然很有用,但也有明显的缺点.它将样品的不同属性(即各指标或各变量)之间的差别等同看待,这一点有时不能满足实际要求.例如,在教育研究中,经常遇到对人的分析和判别,个体 ...
-
JustMock .NET单元测试利器(二)JustMock基础
JustMock API基础 Mock是Telerik®JustMock框架中的主要类.Mock用于创建实例和静态模拟,安排和验证行为. 本文将介绍 "Mock"的基本用法: 首先 ...
-
linux下的QT打包方法
一句话很简单,一个shell脚本搞定,不跟你嘻嘻哈哈 #!/bin/shexe="ThorIceLocker"#存放你的可执行文件的名字des="/home/ninetr ...
-
前端使用 validate , 根据条件进行动态的验证添加
需求如下: 审核操作的时候,选择“通过” 就不需要验证审核意见,但是选择的是“不通过”,那么需要进行审核意见验证 <script> $(function () { InitValidate ...
-
apiCloud app调用浏览器打开网页的方法
在APP调用浏览器有两种方法:1.使用openApp2.使用openWin 两种方法调用浏览器后的效果有一点不同:1.使用openApp调用浏览器后,如果手机内有多个浏览器,会首先弹出选择浏览器的框2 ...