数据采集与融合技术第四次大作业
作业①
1.实验内容
- 要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;Scrapy+Xpath+MySQL数据库存储技术路线爬取当当网站图书数据
- 候选网站:http://search.dangdang.com/?key=python&act=input
- 关键词:学生可自由选择
- 输出信息:MySQL的输出信息如下。
- 运行结果截图:(运行结果较多只截取部分信息)
控制台截图:
数据库截图:
2.心得体会
(1)本题是对利用scrapy对当当网进行数据爬取代码的复现,以爬取关键词为哈利波特为例。
(2)Scrapy框架思路:
(3)访问网页并进行元素审查,尤其是翻页部分
可以发现下一页的网址在li[class=”next”]的子节点a属性herf中
(4)items:定义数据结构供Spider、pipelines调用,在items.py文件中设置各类参数。
class DdscrapyItem(scrapy.Item):
# define the fields for your item here like:
id = scrapy.Field() #序号
title = scrapy.Field() #标题
author = scrapy.Field() #作者
publisher = scrapy.Field() #出版社
date = scrapy.Field() #时间
price = scrapy.Field() #价格
detail = scrapy.Field() #详细信息
pass
(5)pipelines调用items中的信息,将封装好的信息解析出来存储到本地,所以在pipelines.py文件中进行数据库存储。
- 编写open_spider()函数进行连接数据库
- 编写close_spider()函数进行关闭数据库
- 编写process_item()函数将爬取过程打印并将数据写入数据库中
(6)在spider文件夹下新建myspider.py文件并在start_requests函数中编写首次访问请求,在parse函数中获取所需数据,并注意翻页的相关信息爬取。
def start_requests(self): #首次爬取
yield scrapy.Request(url=MySpider.url,callback=self.parse)
def parse(self, response): #获取数据
try:
dammit = UnicodeDammit(response.body, ["utf-8", "gbk"])
data = dammit.unicode_markup
selector = scrapy.Selector(text=data)
lis = selector.xpath("//li['@ddt-pit'][starts-with(@class,'line')]")
for li in lis:
MySpider.count +=1
title = li.xpath("./a[position()=1]/@title").extract_first()
price =li.xpath("./p[@class='price']/span[@class='search_now_price']/text()").extract_first()
author = li.xpath("./p[@class='search_book_author']/span[position()=1]/a/@title").extract_first()
date = li.xpath("./p[@class='search_book_author']/span[position()=last()- 1]/text()").extract_first()
publisher = li.xpath("./p[@class='search_book_author']/span[position()=last()]/a/@title ").extract_first()
detail = li.xpath("./p[@class='detail']/text()").extract_first()
item = DdscrapyItem()
item["id"] = MySpider.count
item["title"] = title.strip() if title else "None"
item["author"] = author.strip() if author else "None"
item["date"] = date.strip()[1:] if date else "None"
item["publisher"] = publisher.strip() if publisher else "None"
item["price"] = price.strip() if price else "None"
item["detail"] = detail.strip() if detail else "None"
#如果没有提取到信息则返回无
yield item #返回获取对象
if MySpider.page <= 2: #爬取3页,在原来已经爬取第一页的基础上进行判断
MySpider.page += 1
new_page_url = self.url % MySpider.page
yield scrapy.Request(url=new_page_url, callback=self.parse)
except Exception as err:
print(err)
(7)在setting.py文件中设置打开pipeline的相关信息
ITEM_PIPELINES = {
'ddscrapy.pipelines.DdscrapyPipeline': 300,
}
(8)编写run.py文件进行运行
from scrapy import cmdline
cmdline.execute("scrapy crawl HarryPotter -s LOG_ENABLED=False".split())
(9)遇到的问题及解决
在爬取过程中通过控制台打印的信息发现数据库总共只存储了162条信息,而一共爬取了180条信息。
查看控制台输出的信息发现detail中超出varchar的最大长度
于是在数据库中将表中bDetail类型修改为longtext
重新运行发现成功存储180条信息
作业②
1.实验内容
- 要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取外汇网站数据。
- 候选网站:招商银行网:http://fx.cmbchina.com/hq/
- 输出信息:MySQL数据库存储和输出格式
Id | Currency | TSP | CSP | TBP | CBP | Time |
---|---|---|---|---|---|---|
1 | 港币 | 86.60 | 86.60 | 86.26 | 85.65 | 15:36:30 |
2...... |
- 运行结果截图:
控制台截图:
数据库截图:
2.心得体会
(1)Scrapy框架思路:
(2)访问网页并进行元素审查
可以本题的数据较小,而且每条数据的标签及其属性都很相似,因而爬取过程中需要注意爬取的是哪一个数据。
(3)items:定义数据结构供Spider、pipelines调用,在items.py文件中设置各类参数。
class FcurrencyItem(scrapy.Item):
# define the fields for your item here like:
id = scrapy.Field()
currency = scrapy.Field()
TSP = scrapy.Field()
CSP = scrapy.Field()
TBP = scrapy.Field()
CBP = scrapy.Field()
time = scrapy.Field()
pass
(4)pipelines调用items中的信息,将封装好的信息解析出来存储到本地,所以在pipelines.py文件中进行数据库存储。
- 初始化数据库,利用setting中所写的本地数据库信息进行数据库的连接
def __init__(self):
self.connect = pymysql.connect(
host=settings.MYSQL_HOST,
db=settings.MYSQL_DBNAME,
user=settings.MYSQL_USER,
passwd=settings.MYSQL_PASSWD,
charset='utf8',
use_unicode=True) #连接数据库
self.cursor = self.connect.cursor();
- 打印爬取信息并将爬取数据存入数据库中
def process_item(self, item, spider):
try:
print("{:^5}\t{:^5}\t{:^5}\t{:^5}\t{:^5}".format(item["id"],item["TSP"],item["CSP"],item["TBP"],item["CBP"],item["time"]))
except Exception as err:
print(err)
try:
self.cursor.execute(
"""insert into fcurrency(Id, Currency, TSP, CSP, TBP, CBP , T)
value (%s, %s, %s, %s, %s, %s, %s)""",
(item['id'],
item['currency'],
item['TSP'],
item['CSP'],
item['TBP'],
item['CBP'],
item['time']))
# 提交sql语句
self.connect.commit()
except Exception as error:
# 出现错误时打印错误日志
print(error)
return item
(7)在spider文件夹下新建myspider.py文件并在start_requests函数中编写首次访问请求,在parse函数中获取所需数据,并注意翻页的相关信息爬取。
def start_requests(self): #访问网页
url = 'http://fx.cmbchina.com/hq/'
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response): #获取数据
try:
dammit = UnicodeDammit(response.body, ["utf-8", "gbk"])
data = dammit.unicode_markup#解码
selector = scrapy.Selector(text=data)
currencys = selector.xpath("//table[@class='data']//tr")
for currency in currencys[1:]:
MySpider.count+=1
Currency = currency.xpath("./td[@class='fontbold']/text()").extract_first()
TSP = currency.xpath("./td[@class='numberright']/text()").extract_first()
CSP = currency.xpath("./td[@class='numberright']/text()")[1].extract()
TBP = currency.xpath("./td[@class='numberright']/text()")[2].extract()
CBP = currency.xpath("./td[@class='numberright']/text()")[3].extract()
Time = currency.xpath("./td[@align='center']/text()")[2].extract()
item = FcurrencyItem()
item["id"] = MySpider.count
#获取信息中的文本内容
item["currency"] = Currency.strip()
item["TSP"] = TSP.strip()
item["CSP"] = CSP.strip()
item["TBP"] = TBP.strip()
item["CBP"] = CBP.strip()
item["time"] = Time.strip()
yield item
print(currencys)
except Exception as err:
print(err)
(6)在setting.py文件中设置网络代理和与数据库连接相关的变量
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
MYSQL_HOST = 'localhost'
MYSQL_DBNAME = 'ex4'
MYSQL_USER = 'root'
MYSQL_PASSWD = '123456'
ITEM_PIPELINES = {
'fcurrency.pipelines.FcurrencyPipeline': 300,
}
(8)编写run.py文件进行运行
from scrapy import cmdline
print("{:^5}\t{:^5}\t{:^5}\t{:^5}\t{:^5}".format("Id","Currency","TSP","CSP","TBP","CBP","Time"))
cmdline.execute(['scrapy','crawl','fcurrency','--nolog'])
作业③
1.实验内容
- 要求:熟练掌握 Selenium 查找HTML元素、爬取Ajax网页数据、等待HTML元素等内容;使用Selenium框架+ MySQL数据库存储技术路线爬取“沪深A股”、“上证A股”、“深证A股”3个板块的股票数据信息。
- 候选网站:东方财富网:http://quote.eastmoney.com/center/gridlist.html#hs_a_board
- 输出信息:MySQL数据库存储和输出格式如下,表头应是英文命名例如:序号id,股票代码:bStockNo……,由同学们自行定义设计表头:
序号 | 股票代码 | 股票名称 | 最新报价 | 涨跌幅 | 涨跌额 | 成交量 | 成交额 | 振幅 | 最高 | 最低 | 今开 | 昨收 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 688093 | N世华 | 28.47 | 62.22% | 10.92 | 26.13万 | 7.6亿 | 22.34 | 32.0 | 28.08 | 30.2 | 17.55 |
2...... |
- 运行结果部分截图:
控制台截图:
数据库截图:
2.心得体会
(1)本次需要爬取3个板块的数据,所以要查看3个板块网址直接的规律
- 沪深A股:http://quote.eastmoney.com/center/gridlist.html#hs_a_board
- 上证A股:http://quote.eastmoney.com/center/gridlist.html#sh_a_board
- 深证A股:http://quote.eastmoney.com/center/gridlist.html#sz_a_board
可以发现各版块的网址在html#后不同,其他均相同,可以设置一个start_url和字符进行一个连接同时利用多线程对3个网页进行爬取加快速度
start_url = "http://quote.eastmoney.com/center/gridlist.html#%s"
shares = ["hs_a_board", "sh_a_board", "sz_a_board"]
for share in shares:
url = start_url % share
T = threading.Thread(target=Spider(url)) #设置多线程
T.setDaemon(False)
T.start()
time.sleep(random.randint(1,3))
(2)对于翻页,检查下一页的元素,然后利用click()动作进行翻页
nextpage=driver.find_element_by_xpath("//div[@id='main-table_paginate']/a[2]")
nextpage.click()
(3)建立Chrome浏览器的访问请求
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options)
(4)对每页数据利用xpath语句进行获取,其中每页第一行数据(list[0])为标题,所以从第二行(list[1])开始获取数据。
for li in list[1:]:
no = li.find_element_by_xpath(("./td[1]")).text
code = li.find_element_by_xpath(("./td[2]")).text
name = li.find_element_by_xpath(("./td[3]")).text
newprice = li.find_element_by_xpath(("./td[5]")).text
up = li.find_element_by_xpath(("./td[6]")).text
down = li.find_element_by_xpath(("./td[7]")).text
num = li.find_element_by_xpath(("./td[8]")).text
count = li.find_element_by_xpath(("./td[9]")).text
swing = li.find_element_by_xpath(("./td[10]")).text
high = li.find_element_by_xpath(("./td[11]")).text
low = li.find_element_by_xpath(("./td[12]")).text
today = li.find_element_by_xpath(("./td[13]")).text
yes = li.find_element_by_xpath(("./td[14]")).text
(5)建立与数据库的连接,并将爬取的数据存储到数据库中
db = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="123456", db="ex4", charset="utf8") #连接本地数据库
cursor = db.cursor()
try:
cursor.execute("""insert into shares(no,code,name,newprice,up,down,num,count,swing,high,low,today,yes) value (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"""
,(no, code, name, newprice, up, down, num, count, swing, high, low, today,yes)) #将数据插入数据库中
db.commit() #提交
except Exception as err:
print(err)
(6)遇到的问题及解决
在进行翻页的时候出现报错:
检查之后发现在翻页时忘记设置休眠时间,使得翻页速度跟不上爬取速度,因而在翻页时要设置一定的翻页时间