How to save tweets from TweetStream with SQLite3 and Ruby - ruby

I am very new to ruby and RoR. I would like to save incoming tweets that are currently being displayed on my terminal. Could you explain why the tweets are not being saved?
I run " ruby mine_tweets.rb" in the terminal and the the "puts" of the status.text appears, but there are no entries in the database.
mine_tweets.rb
require 'rubygems'
require 'tweetstream'
puts "searching for turkey....should write to database"
TweetStream.configure do |config|
config.consumer_key = 'XXXXXXX'
config.consumer_secret = 'XXXXXXX'
config.oauth_token = 'XXXXXXX'
config.oauth_token_secret = 'XXXXXXX'
config.auth_method = :oauth
end
# search for "turkey" and will print text and screen name and should store other values in db
TweetStream::Client.new.track('turkey') do |status|
puts status.text + " FROM: #" + status.user.screen_name
Tweet.create(:user_id => status.user.id, :tweet_text => status.text, :screen_name =>status.user.screen_name)
Tweet.save!
end
#client = TweetStream::Client.new
#client.on_delete do |status_id, user_id|
Tweet.delete(status_id)
end
model/tweets.rb
class Tweet < ActiveRecord::Base
attr_accessible :screen_name, :tweet_text, :user_id
end

I recently struggled through this myself. Here is what I found:
In order to save to a database, you need to :
create a database.
connect application to db.
create table and columns
..do something, ie. save, query etc.
close connection (before exiting app)
Here is how i was able to save tweets from the Tweet Stream api into a sqlite local database. (I highly recommend switching directly to Postgres since Heroku doesn't support sqlite).
tweetstream.rb
require 'sqlite3'
require 'tweetstream'
KEY = 'xxx'
SECRET = 'xxx'
TOKEN = 'xxx'
TOKEN_SECRET = 'xxx'
SEARCH_TERMS = "your search terms"
begin
db = SQLite3::Database.open "./db/tweets.db"
db.execute "CREATE TABLE IF NOT EXISTS store_tweets(
id, INTEGER PRIMARY KEY,
tweetid TEXT,
text TEXT,
screen_name TEXT,
userid TEXT,
user_name TEXT,
profile_image_url TEXT,
language,
created_at TEXT,
received_at TIMESTAMPS)"
TweetStream.configure do |config|
config.consumer_key = KEY
config.consumer_secret = SECRET
config.oauth_token = TOKEN
config.oauth_token_secret = TOKEN_SECRET
config.auth_method = :oauth
end
TweetStream::Client.new.track(SEARCH_TERMS) do |status|
puts "#{status.text}"
db.execute( "INSERT INTO store_tweets(
'tweetid',
'text',
'screen_name',
'userid',
'user_name',
'profile_image_url',
'language')
VALUES (?, ?, ?, ?, ?, ?, ?)",
[status[:id]],
[status.text],
[status.user.screen_name],
[status.user[:id]],
[status.user.name],
[status.user.profile_image_url],
[status.lang])
end
rescue SQLite3::Exception => e
puts "Exception occured"
puts e
ensure
db.close if db
end

Related

Twilio SMS using Ruby

I've been working on a program that would read a CSV excel file and filter the information to be sent via sms. Currently, the program is only able to send one row of filtered information via sms. What should be modified to be able to send row after row seperately?
Currently the code searches for 'medium' and '2' on columns 1 and 2. It would send out columns 0 and 4. Hence the results would be "DT3/SIG, "Repair Windows"
but it wouldnt send out row 5 - "90430/RSO", "Repair Lights"
require 'rubygems'
require 'twilio-ruby'
require "csv"
def load_alarms
CSV.read 'alarms.csv', {col_sep: ';'}
end
def filter_by_event_type_and_severity(alarms, event_type, severity)
alarms.select do |alarm|
alarm[1] == event_type && alarm[2].to_i == severity.to_i
end
end
target_alarms = filter_by_event_type_and_severity(
load_alarms, 'medium', 2)
equipments = target_alarms.map { |alarm| [alarm[0], alarm[3]] }
p equipments
account_sid = 'ACCOUNT_ID'
auth_token = 'AUTH_TOKEN'
client = Twilio::REST::Client.new account_sid, auth_token
client.api.account.messages.create(
from: 'SENDER_PHONE',
to: 'TARGET_PHONE',
body: equipments
)
As i wrote in the comment, all you need to do is iterate over the equipments you got from the filter_by_event_type_and_severity method, and send them one by one with the twillo api:
require 'rubygems'
require 'twilio-ruby'
require "csv"
def load_alarms
CSV.read 'alarms.csv', {col_sep: ';'}
end
def filter_by_event_type_and_severity(alarms, event_type, severity)
alarms.select do |alarm|
alarm[1] == event_type && alarm[2].to_i == severity.to_i
end
end
target_alarms = filter_by_event_type_and_severity(load_alarms, 'medium', 2)
equipments = target_alarms.map { |alarm| [alarm[0], alarm[3]] }
account_sid = 'ACCOUNT_ID'
auth_token = 'AUTH_TOKEN'
client = Twilio::REST::Client.new account_sid, auth_token
# Here is the iteration
equipments.each do |equipment|
client.api.account.messages.create(
from: 'SENDER_PHONE',
to: 'TARGET_PHONE',
body: equipment
)
end
I removed your account_id, auth_token and phone numbers, so you need to add them back

display postgres sql result using pg gem

How do I display the result set of a postgres query using the pg gem only ? I want it to be in tabular form like it is in pgAdmin GUI tool. The code below does not help. The documentation is not clear, so I am unable to figure another way out. Please help !
require 'pg'
conn = PGconn.connect("db.corp.com", 5432, '', '', "schema", "user", "pass")
sql = 'select * from tbl limit 2'
res = conn.exec(sql)
res.each do |row|
row.each do |column|
end
end
gem list -
pg (0.9.0.pre156 x86-mswin32)
ruby - 1.8.7
Steps -
1. Get list of column names in result set (type PGResult).
2. Iterate each row(hash) of result set.
3. For each row (hash key)/columns found in step 1, find the column values (hash value).
Then print results as csv. I dont think this is efficient, but it gets the job done.
require 'pg'
conn = PGconn.connect("db.corp.com", 5432, '', '', "schema", "user", "pass")
sql = 'select * from tbl limit 2'
res = conn.exec(sql)
rows_count = res.num_tuples
column_names = res.fields
col_header = column_names.join(', ')
puts col_header
for i in 0..rows_count-1
row_hash = res[i]
row_arr = []
column_names.each do |col|
row_arr << row_hash[col]
end
row = row_arr.join(', ')
puts row
end

Ruby <NoMethodError>

I'm using the following script to download FFFFound entire directory images but im having an issue, after the first batch of files Im getting this error message:
ffffound_mirror_db.rb:45in 'block in populate_db': undefined method 'inner_html' for nil:NilClass <NoMethodError>
from ffffound_mirror_db.rb:39:in 'each'
from ffffound_mirror_db.rb:39:in 'populate_db'
from ffffound_mirror_db.rb:190:in <main>
I'm trying to download all the 99 pages of a directory so the offset has to increase 25 every batch, eg: 0, 25, 50, 75, 100
#!/usr/bin/ruby
require 'rubygems'
require 'etc'
require 'hpricot'
require 'json'
require 'open-uri'
require 'sqlite3'
require 'time'
require 'date'
require 'fileutils'
def populate_db(db, user, type)
domain = "http://ffffound.com/"
offset = 0
images_sql = <<EOS
INSERT OR REPLACE INTO
images (id, url, src, title, orig_url, orig_src, count, date, related)
values (:id, :ffffound_url, :ffffound_img, :title, :orig_url, :orig_img, :count, :date, :rel)
EOS
images_ins = db.prepare(images_sql)
# related_ins = db.prepare( "insert into related values (?, ?, ?)" )
img = []
while
if user == "all" # wow, this is naughty
doc = Hpricot(open("#{ domain }/?offset=#{ offset }&"))
else
doc = Hpricot(open("#{ domain }/home/#{ user }/#{ type }/?offset=#{ offset }&"))
end
images = (doc/"blockquote.asset")
puts "Got #{ images.size.to_s } images at offset #{ offset.to_s }"
break if (images.size == 0)
images.each do |image|
# can I make this block into a method somehow?
info = {}
# image title
title_elem = (image/"div.title")
info[:title] = title_elem.at("a").inner_html
# original source image
src_elem = (image/"div.title")
info[:orig_url] = src_elem.at("a")["href"]
# from description, break out img url, date posted (relative!), count
desc_elem = (image/"div.description")
desc = desc_elem.inner_html
info[:orig_img] = desc.gsub(/<br ?\/?>.*/, "")
datestr = desc.gsub(/.*<br ?\/?>/, "")
datestr = datestr.gsub(/<a h.*/, "")
datestr = datestr+" +0900" # ffffound uses Japanese time, UTC +0900
begin
dt = Time.parse(datestr)
rescue
end
info[:date] = dt.to_i
count = desc_elem.at("a").inner_text
count = count.gsub(/[\D]/, "")
info[:count] = count
# ffffound image URL and page URL, and ffffound ID (could generate
# URL from ID but would lose ?c form; src would lose _m)
image_block = (image/"table td")
ffffound_url = image_block.at("a")['href']
ffffound_img = image_block.at("img")['src']
id = ffffound_img
id = ffffound_img.split('/')[6]
id = id.gsub(/_.*/, "")
info[:id] = id
info[:ffffound_url] = ffffound_url
info[:ffffound_img] = ffffound_img
download_file(ffffound_img, id)
# might as well get related asset IDs
rel = Array.new
relateds = (image/"div.related_to_item_xs")
relateds.each do |related|
path = related.at("a")['href']
id = path[ path.index(/\//, 2)+1 .. -1 ]
rel.push(id)
# TODO normalised table for related IDs
end
info[:rel] = rel.join(",")
img.unshift(info)
# put in db
images_ins.execute(info)
end
break if (images.size < 25) # more efficient than doing another fetch
offset = offset + 25
end
puts "Got #{ img.size } images"
end
def create_db(db)
images = <<EOC
CREATE TABLE IF NOT EXISTS
images (id TEXT PRIMARY KEY,
url TEXT,
src TEXT,
title TEXT,
orig_url TEXT,
orig_src TEXT,
date INTEGER,
count INTEGER,
related TEXT,
posted BOOL);
EOC
related = <<EOC
CREATE TABLE IF NOT EXISTS
related (id INTEGER PRIMARY KEY,
source INTEGER
related INTEGER);
EOC
tumblr = <<EOC
CREATE TABLE tumblr (id INTEGER PRIMARY KEY,
ffffound_id TEXT,
tumblr_id INTEGER,
create_status INTEGER,
edit_status INTEGER);
EOC
db.execute(images)
db.execute(related)
return true
end
def download_file(url, id)
# TODO file type awareness
# does it exist?
if not File.exist?('images/'+id+'.jpg')
writeOut = open("images/"+id+'.jpg', 'wb')
writeOut.write(open(url).read)
writeOut.close
puts ' downloaded ' + id
end
end
def create_paths()
['images', 'db'].each do |path|
if not File.exist?(path)
FileUtils.mkdir(path)
end
end
end
# this needs work (is there a more idiomatic way to do this?)
user = ARGV[0]
type = ARGV[1] || 'found'
if not user
puts "A ffffound username must be supplied"
exit
else
if user == "--all"
puts "Invoked for all posts"
user = "all"
end
puts "Invoked for posts by #{user} of type #{type}"
end
create_paths()
path = 'db/ffffound-'+user+'.db' # ick
db = SQLite3::Database.new(path)
create_db(db)
populate_db(db, user, type)
exit
# puts img.to_json
# DONE puts img.to_database_table(s)
In these 2 parts:
title_elem = (image/"div.title")
info[:title] = title_elem.at("a").inner_html
desc_elem = (image/"div.description")
desc = desc_elem.inner_html
You don't check if elem exists, but calling inner_html right after. So, basically, if desc_elem is nil, you call nil.inner_html which raises exception, because there is no such method for nil.
To fix this, replace corresponding lines with(for Ruby without Rails)
title_elem = (image/"div.title")
info[:title] = title_elem.at("a").inner_html unless title_elem.at("a").nil?
desc_elem = (image/"div.description")
desc = desc_elem.inner_html unless desc_elem.nil?
In Rails there is a .try method, which prevents such exception raising, so
title_elem = (image/"div.title")
info[:title] = title_elem.at("a").try(:inner_html)
desc_elem = (image/"div.description")
desc = desc_elem.try(:inner_html)
is a solution if you are using Rails.

How can I retrieve my profile with the twitter gem

client = Twitter::REST::Client.new do |config|
config.consumer_key = "XX"
config.consumer_secret = "XY"
config.access_token = "ZZ"
config.access_token_secret = "ZZZ"
end
How can I retrieve my profile information?
You can do the following simple steps to use the Twitter client gem:
# get user id from user name
id = client.user( 'user_name' ).id
# read user's timeline by id
timeline = client.user_timeline id
# read user's timeline of yours
your_timeline = client.user_timeline
you can omit the username, and you get the timeline of current user, so try also to issue:
user_info = client.user

How can I store user defined data in a hash

Help, I am a noob, just need some advice on this bit of code. I have got most of my program working this part has me stuped i want to get a name and password. Then make the name the key and the password the value. Now it must be user defined.. Then I must be able to pull that hash info again. I thought that return would work... here is my code
def login_prompt
vault = {}
puts "WELCOME! please enter an existing username: "
username = gets.chomp
checkname = Noxread.new
comparename = checkname.read_file
comparename.keys.include?("#{username}")
if comparename == true
puts "please enter your password: "
password = gets.chomp
vault[username]= password
else puts "username already exists!! would you like to retry? (y/n)"
case answer
when /^y/
login_prompt
when /^n/
exit
end
end
end
so that should gather the info. and this is my code to merge that and an hash that i pulled from a file. in a NoxRead class
require_relative 'read'
require 'csv'
class Noxwrite
attr_accessor :name :password
def initialize
#name = name
#password = password
end
def upsum
x = Noxread.new
y = x.read_file
z = login_prompt
y.merge(z) {|name, password| name + ',' + password}
return y
end
def write_file
ehash = upsum
CSV.open("data.csv", "wb") do |csv|
csv << ehash
end
end
end
What is the problem with this code. Seems fine, apart from the fact that passwords should not be read like this in open text.
When you write something like
user_hash = login_prompt
user_hash will have the hash as desired
{"username"=>"password"}

Resources