存储数据
in Web Crawler 访问: 489 次 with 0 comment

存储数据

in Web Crawler with 0 comment

j_YWoV_uzRw.jpg

存储数据

媒体文件

存储媒体文件有两种主要的方式:只获取文件 URL 链接,或者直接把源文件下载下来。

下载 logo 图片,然后在程序运行的文件夹里保存为 logo.jpg 文件。

#scrapetest.py
from urllib.request import urlopen
from urllib.request import urlretrieve
from bs4 import BeautifulSoup

html = urlopen("http://www.pythonscraping.com")
bs_obj = BeautifulSoup(html,"xml")
image_location = bs_obj.find("a",{"id":"logo"}).find("img")["src"]
urlretrieve(image_location,"logo.jpg") 

所有 src 属性的文件都下载下来

#scrapetest.py
import os
from urllib.request import urlopen
from urllib.request import urlretrieve
from bs4 import BeautifulSoup

download_directory = "downloaded"
base_url = "http://pythonscraping.com"

def get_absolute_url(base_url,source):
    if source.startswith("http://www."):
        url = "http://" + source[11:]
    elif source.startswith("http://"):
        url = source
    elif source.startswith("www."):
        url = source[4:]
        url = "http://" + source
    else:
        url = base_url + "/" + source
    if base_url not in url:
        return None
    return url

def get_download_path(base_url, absolute_url, download_directory):
    path = absolute_url.replace("www.","")
    path = path.replace(base_url,"")
    path = download_directory + path
    directory = os.path.dirname(path)

    if not os.path.exists(directory):
        os.makedirs(directory)
    return path

html = urlopen("http://www.pythonscraping.com")
bs_obj = BeautifulSoup(html,"xml")
download_list = bs_obj.findAll(src = True)

for download in download_list:
    file_url = get_absolute_url(base_url,download["src"])
    if file_url is not None:
        print(file_url)

urlretrieve(file_url,get_download_path(base_url,file_url,download_directory))

os 模块用来获取每个下载文件的目标文件夹,建立完整的路径。os 模块是
Python 与操作系统进行交互的接口,它可以操作文件路径,创建目录,获取运行进程和环境变量的信息,以及其他系统相关的操作。

把数据存储到CSV

CSV 里留白:每一行都用一个换行符分隔,列与列之间用逗号分隔

import csv

csv_file = open("../Python网络数据采集/files/test.csv","w+")
try:
    writer = csv.writer(csv_file)
    writer.writerow(('number','number plus 2', 'number times 2'))
    for i in range(10):
        writer.writerow((i, i+2, i*2))
finally:
    csv_file.close()

如果文件不存在,Python 会自动创建文件(不会自动创建文件夹)。如果文件已经存在,Python 会用新的数据覆盖 原来的 csv文件。

#scrapetest.py
import csv
from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("http://en.wikipedia.org/wiki/Comparison_of_text_editors")
bs_obj = BeautifulSoup(html,"xml")

# 主对比表格是当前页面上的第一个表格
table = bs_obj.findAll("table",{"class":"wikitable sortable"})[0]
rows = table.findAll("tr")

csv_file = open("../Python网络数据采集/files/test.csv","w+", newline = '', encoding = 'utf-8')
try:
    writer = csv.writer(csv_file)
    for row in rows:
        csv_row = []
        for cell in row.findAll(['td','th']):
            csv_row.append(cell.get_text())
            writer.writerow(csv_row)
finally:
    csv_file.close()

MySQL

MySQL 语句是不区分大小写的。

终端

cd /usr/local/mysql/bin/ 进入
mysql -uroot -p  启动

CREATE DATABASE 创建数据库
USE             使用数据库

MySQL 数据表必须至少有一列,否则不能创建。为了在 MySQL 里定义字
段(数据列),你必须在 CREATE TABLE <tablename> 语句后面,把字段的定义放进一个带括号的、内部由逗号分隔的列表中:

CREATE TABLE pages (id BIGINT(7) NOT NULL AUTO_INCREMENT, title VARCHAR(200), content VARCHAR(10000), created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id));
DESCRIBE 查看数据表的结构
 INSERT INTO 插入数值
SELECT * FROM 表 WHERE 条件; 查找数据
DELETE FROM 表 WHERE 条件;

由于数据库的数据删除后不能恢复,所以在执行 DELETE 语句之前,建议用 SELECT 确认一下要删除的数据

UPDATE 表 SET 属性=属性值, 属性=属性值 WHERE 条件;
MySQL与Python整合

如果你的 MySQL 服务器处于运行状态, 应该就可以成功地执行下面的命令(记得把 root 账户密码加进去):

import pymysql
conn = pymysql.connect(host = '127.0.0.1', unix_socket='/tmp/mysql.sock', user='root', passwd=None, db='mysql')

cur = conn.cursor()
cur.execute("USE scraping")

cur.execute("SELECT * FROM pages WHERE id=1")
print(cur.fetchone())
cur.close()
conn.close()

连接对象(conn)和光标对象(cur)

连接模式除了要连接数据库之外,还要发送数据库信息,处理回滚操作(当一个查询或一组查询被中断时,数据库需要回到初始状态,一般用事务控制手段实现状态回滚),创建新的光标对象,等等

一个连接可以有很多个光标。一个光标跟踪一种状态(state)信息,比如跟踪数据库的使用状态。如果你有多个数据库,且需要向所有数据库写内容,就需要多个光标来处理。光标还会包含最后一次查询执行的结果。通过调用光标函数,比如 cur.fetchone(),可以获取查询结果。

用完光标和连接之后,千万记得把它们关闭。如果不关闭就会导致连接泄漏(connectionleak),造成一种未关闭连接现象,即连接已经不再使用,但是数据库却不能关闭,因为数据库不能确定你还要不要继续使用它。这种现象会一直耗费数据库的资源

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import datetime
import random
import pymysql
conn = pymysql.connect(host = '127.0.0.1', unix_socket='/tmp/mysql.sock', user='root', passwd=None, db='mysql',charset='utf8')

cur = conn.cursor()
cur.execute("USE scraping")

random.seed(datetime.datetime.now())

def store(title,content):
    cur.execute("INSERT INTO pages (title, content) VALUES (\"%s\",\"%s\")",(title,content))
    cur.connection.commit()

def get_links(article_url):
    html =  urlopen("http://en.wikipedia.org" + article_url)
    bs_obj = BeautifulSoup(html,"xml")
    title = bs_obj.find("title").get_text()
    content = bs_obj.find("div", {"id":"mw-content-text"}).find("p").get_text()
    store(title, content)
    return bs_obj.find("div", {"id":"bodyContent"}).findAll("a",href=re.compile("^(/wiki/)((?!:).)*$"))

links = get_links("/wiki/Kevin_Bacon")

try:
    while len(links) > 0:
        new_article = links[random.randint(0,len(links)-1)].attrs['href']
        print(new_article)
        links = get_links(new_article)
finally:
    cur.close()
    conn.close()

除非你安装了第三方包或保存详细的数据库日志,否则你无法掌握数据库里数据增加、更新或删除的具体时间。因此,如果需要对数据可用的空间、变更的频率和变更的重要性进行分析,你应该考虑在数据新增、更新或删除时加一个时间戳。

MySQL里的“六度空间游戏”
CREATE TABLE `wikipedia`.`pages` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `url` VARCHAR(255) NOT NULL,
    `created` TIMESTAMP NOT NULL DEFAULT
    CURRENT_TIMESTAMP, PRIMARY KEY (`id`));
CREATE TABLE `wikipedia`.`links` ( 
    `id` INT NOT NULL AUTO_INCREMENT, 
    `fromPageId` INT NULL,
    `toPageId` INT NULL,
    `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    PRIMARY KEY (`id`));
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import pymysql

conn = pymysql.connect(host = '127.0.0.1', unix_socket='/tmp/mysql.sock', user='root', passwd='liudongqi', db='mysql',charset='utf8')

cur = conn.cursor()
cur.execute("USE wikipedia")

pages = set()

def insert_page_if_not_exists(url):
    cur.execute("SELECT * FROM pages WHERE url = %s", (url))
    if cur.rowcount == 0:
        cur.execute("INSERT INTO pages (url) VALUES (%s)", (url))
        conn.commit()
        return cur.lastrowid
    else:
        return cur.fetchone()[0]

def insert_link(fromPageId, toPageId):
    cur.execute("SELECT * FROM links WHERE fromPageId = %s AND toPageId = %s",(int(fromPageId),int(toPageId)))
    if cur.rowcount == 0:
        cur.execute("INSERT INTO links (fromPageId, toPageId) VALUES(%s, %s)",(int(fromPageId),int(toPageId)))
        conn.commit()

def get_links(page_url, recursion_level):
    global pages
    if recursion_level > 4:
        return;
    page_id = insert_page_if_not_exists(page_url)
    html =  urlopen("http://en.wikipedia.org" + page_url)
    bs_obj = BeautifulSoup(html,"xml")
    for link in bs_obj.findAll("a", href=re.compile("^(/wiki/)((?!:).)*$")):
        insert_link(page_id, insert_page_if_not_exists(link.attrs['href']))
        if link.attrs['href'] not in pages:
            # 遇到一个新页面,加入集合并搜索里面的词条链接
            new_page = link.attrs['href']
            pages.add(new_page)
            get_links(new_page, recursion_level + 1)

get_links("/wiki/Kevin_Bacon", 0)
cur.close()
conn.close()
Responses