环境是python3.6.5以及PyCharm不得不说,JetBrains做的IDE都很不错,无论是这款PyCharm还是IntelliJ、Goland在形参处的名称提示太方便了
爬虫就是建立一个与某个网站的连接 通过该连接获取输入流,读取网站内容 实质上就是一个socket的输入输出操作,根据http状态码以及请求头里的信息,验证是否发送完毕(一般是200),结束连接
网络爬虫
本次使用的爬取类库是python3.6的一个标准库 urllib不依赖任何第三方库,无需安装 通过以下代码
req=urllib.request.Request(url,header)
可以得到一个HttpRequest对象 再通过以下代码,发出该请求并得到一个HttpResponse对象
res=urllib.request.urlopen(req,context)
以上代码中,如果是http:开头的网站header和context都可以省略,则采用默认参数 而对于https开头的网站,因为要进行证书验证 所以要创建一个带ssl证书的context并传入
context = ssl._create_unverified_context()
通过以下方式创建header来指定模拟爬虫的浏览器信息 并在网站支持国际化时指定语言为中文
header = {
'Accept': 'text/html, application/xhtml+xml, */*',
'Accept-Language': 'zh-CN',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
'DNT': '1',
'Connection': 'Keep-Alive',
}
通过得到的response对象的read方法会返回页面内容的byte数组 而我们需要的是字符串 所以使用decode方法,对byte数组编码并转换成字符串 而网络传输的数据格式是json,所以使用json模块的load方法将得到的数据转换为json对象 总结以上几步,我们封装一下爬取资源的方法
def getUrlJson(inUrl):
req = urllib.request.Request(url=inUrl, headers=webheader)
webPage = urllib.request.urlopen(req,context=context)
data = webPage.read().decode('utf-8')
data = json.loads(data)
return data
通过调用该函数
data = getUrlJson(Url)
这样就得到了网页的内容 有个bug,有时候爬取一些网站会提示页面中存在0x8b这个值不能编码为utf-8中的字符 笔者上网百度了很久,包括在stackOverflow上查看相关问题 发现没有真正能解决的,像(注释掉Accept-encode,不注释对压缩giz进行处理,都不能解决) 然后在PyCharm中进行运行居然又不报这个错了… 也希望知道这个bug解决方法的,联系笔者QQ1183609515,谢谢
本次爬取的是选股宝这个股票网站上面所有股票的信息 作为一个股票网站,实时更新是必须的,所以肯定是个动态网站 选股宝https://xuangubao.cn/dingpan/
选股宝数据 爬取下来页面内容后,输出查看发现与我们在浏览器里看到的页面不同,body中只有空标签 这是因为选股宝为了实时更新页面数据 内容都是通过js定时器定时发送ajax请求以后渲染数据到页面中
在浏览器中打开开发者模式(F12)查看刚刚爬取的网站的网络请求数据 发现有这个请求
getIds 这个url获取到的是所有的股票id 还有另一个重要的url
getInfo 这个url可以根据id获取到对应的股票信息 根据这个:
queryProdCodeUrl='https://wows-api.wallstreetcn.com/v3/aioria/plates/summary/field?ids=all&fields=plate_id,stocks'
prodData = getUrlJson(queryProdCodeUrl)
queryInfoUrl='https://wows-api.wallstreetcn.com/real?fields=prod_name,px_change,last_px,px_change_rate,trade_status,circulation_value,pe_rate,market_value,turnover_ratio'
total=0
for item in prodData['data']['items']:
for iitem in prodData['data']['items'][item][1]['items']:
total=total+1
infoUrl = queryInfoUrl + '&en_prod_code=' + iitem[0]
snapshot = getUrlJson(infoUrl)['data']['snapshot']
snapshot = zip(snapshot['fields'],snapshot[iitem[0]])
for info in snapshot:
print(info[0],':',info[1],end=' ')
print('total:',total)
至此,就完成了爬取股票信息并输出
这里要用到第三方的库 xlwt 这是一个python向excel文件输出内容的库,不依赖其他第三方库 安装后 使用命令
xls = xlwt.Workbook()
sheet = xls.add_sheet('sample')
就创建了一个包含一个sample名字的sheet的xls文件对象 使用命令
sheet.write(row, col, data)
就可以将data的内容输出到该对象的row行从来列的格子 最后调用命令
xls.save(yourSavePath)
就可以把xls文件输出到给定目录 综上,我们只需要 在原有代码里修改下
total=0
xls = xlwt.Workbook()
sheet = xls.add_sheet('sample')
for item in prodData['data']['items']:
for iitem in prodData['data']['items'][item][1]['items']:
total=total+1
infoUrl = queryInfoUrl + '&en_prod_code=' + iitem[0]
snapshot = getUrlJson(infoUrl)['data']['snapshot']
snapshot = zip(snapshot['fields'],snapshot[iitem[0]])
col=0
for info in snapshot:
#print(info[0],':',info[1],end=' ')
sheet.write(total, col, info[1])
col=col+1
infoUrl = queryInfoUrl + '&en_prod_code=' + iitem[0]
snapshot = getUrlJson(infoUrl)['data']['snapshot']
snapshot = zip(snapshot['fields'],snapshot[iitem[0]])
col=0
for info in snapshot:
sheet.write(0, col, info[0])
col=col+1
xls.save(yourSavePath)
最后一段代码是把每个field的名字写入excel的第一行 最终查看目录文件 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uuVUPnOu-1589093220299)(/blog/images/python/excelData.jpg)]
excel结果 去除第一行的field名称 总共12924条股票信息 运行时间差不多一小时,才输出完毕